Это 109-я оригинальная статья без воды.Если вы хотите получить больше оригинальных статей, выполните поиск в официальном аккаунте и подпишитесь на нас~ Эта статья была впервые опубликована в блоге Zhengcaiyun:Некоторые основы маршрутизатора в React
предисловие
Каждый раз, когда разрабатывается новая страница, неизбежно создание нового URL-адреса, который является нашим маршрутом. На самом деле, при разработке маршрута это не просто ссылка, состоящая из нескольких простых слов и слэш-разделителей, иногда можно рассмотреть, есть ли более «изящные» методы и приемы проектирования. И за кулисами, каково сотрудничество между маршрутизацией и компонентами? Поэтому я взял использование Router в React в качестве примера и собрал некоторые знания, которыми хочу поделиться с вами~
React-Router
Основное использование
Обычно мы используемReact-RouterЧтобы реализовать управление маршрутизацией о одностранственном приложении Ract React, это реализует переключение компонентов, управляя URL, а затем представляет эффект коммутации страницы.
Его наиболее основное использование выглядит следующим образом:
import { Router, Route } from 'react-router';
render((
<Router>
<Route path="/" component={App}/>
</Router>
), document.getElementById('app'));
Или вложенные маршруты:
До версии React-Router V4 его можно было вложить напрямую, метод следующий:
<Router>
<Route path="/" render={() => <div>外层</div>}>
<Route path="/in" render={() => <div>内层</div>} />
</Route>
</Router>
Теоретически в приведенном выше коде пользователь получает доступ/in
загружается первым<div>外层</div>
, а затем перезагрузить внутри него<div>内层</div>
.
Однако, когда вы действительно запустите приведенный выше код, вы обнаружите, что он отображает содержимое только в корневом каталоге. Последующее сравнение версии React-Router показало, что логика рендеринга была изменена в версии V4. Причина, как говорят, заключается в реализации концепции компонентизации React, а тег Route не может выглядеть как тег (странные знания добавлено).
В более новых версиях вложенность теперь может быть достигнута с помощью метода Render.
<Route
path="/"
render={() => (
<div>
<Route
path="/"
render={() => <div>外层</div>}
/>
<Route
path="/in"
render={() => <div>内层</div>}
/>
<Route
path="/others"
render={() => <div>其他</div>}
/>
</div>
)}
/>
посетить в это время/in
Когда «внешний слой» и «внутренний слой» отображаются вместе, доступ/others
, «Внешний» и «Другой» будут отображаться вместе.
Советы по параметрам маршрутизации
В реальной разработке часто необходимо передавать некоторые параметры при переключении страниц.Некоторые параметры подходят для размещения в Redux в качестве глобальных данных или передачи через контекст, например, некоторые общие бизнес-данные, но некоторые параметры подходят для передачи в URL-адресах. , например Уникальный идентификатор документа в типе страницы или на странице сведений.id
. При работе с URL-адресами, что React-Router может сделать для нас, кроме вопросительного знака с параметрами? Среди них компонент Routepath
Затем атрибуты можно использовать для указания правил сопоставления для маршрутов.
Сцена 1
Описание: Просто хочу сделать обычные URL с обычными параметрами
Итак, далее мы можем сделать это:
Случай A: параметры маршрутизации
path="/book/:id"
Мы можем добавить параметры, которые мы хотим передать в URL-адрес, в виде двоеточия + имя параметра, В это время, когда значение, соответствующее имени параметра (в данном случае id), изменяется, оно будет рассматриваться как другой URL-адрес.
Случай B: параметры запроса
path="/book"
Если вы хотите иметь вопросительный знак с параметрами при переходе на страницу, то путь может быть напрямую спроектирован как заранее определенная форма, а параметры склеиваются перепрыгивающей стороной. При прыжке есть две формы с параметрами. Один из них заключается в том, чтобы передать строку конфигурации в параметре to компонента Link и использовать вопросительный знак для получения параметра, а другой заключается в том, что параметр to может принимать объект, в котором параметры, которые вы хотите передать, могут быть настроены в поле поиска.
<Link to="/book?id=111" />
// 或者
<Link to={{
pathname: '/book',
search: '?id=111',
}}/>
На этом этапе предположим, что когда идентификатор в URL-адресе текущей страницы изменяется со 111 на 222, компонент, соответствующий маршруту (в приведенном выше примере, когда React-Route настроенpath="/book"
соответствующую страницу/компонент)будет обновлять, который выполняет метод componentDidUpdate, ноне будет удален, то есть метод componentDidMount выполняться не будет.
Случай C: Невидимое объединение параметров запроса
path="/book"
Путь по-прежнему проектируется как есть, и при переходе параметры могут быть переданы на соответствующую маршрутизируемую страницу через состояние в Link.
<Link to={{
pathname: '/book',
state: { id: 111 }
}}/>
Но нужно отметить, что хотя параметры запроса не будут передаваться в виде простого текста таким образом, обновление страницы приведет к потере параметров (распространенная проблема, сохраняющаяся в состоянии).Это может быть зашифровано, но в целом, конфиденциальную информацию не рекомендуется передавать в URL~)
сцена 2
Описание: Страница редактирования/детализации, если вы хотите поделиться страницей, URL-адрес различается по разным параметрам. В настоящее время мы надеемся, что параметр должен быть одним из параметров редактирования, детализации и добавления, в противном случае вам нужно перейти к 404 Страница не найдена.
path='/book/:pageType(edit|detail|add)'
Если вы не добавите содержимое в скобках(edit|detail|add)
, при передаче неверных параметров (например, неправильное действие пользователя, случайное сращивание URL-адресов) страница не будет перехвачена 404, а продолжит рендеринг страницы или вызов интерфейса, но в это время, скорее всего, заставить интерфейс передавать параметры Error или page error.
сцена 3
Описание: Новая страница очень похожа на страницу редактирования. Моя новая страница также хочет поделиться той же страницей с редактором/подробностями. Но новой странице не нужен идентификатор, а странице редактирования/деталей нужен идентификатор. Что, если используется та же страница?
path='/book/:pageType(edit|detail|add)/:id?'
Не волнуйтесь, вы можете использовать?
Чтобы решить это, это означает, что id не является необходимым параметром и может быть передан или нет.
сцена 4
Описание: Мой идентификатор может быть только числом. Что делать, если мне не нужна строка?
path='/book/:id(\\\d+)'
В это время, когда идентификатор не является числом, он переходит к 404, и считается, что страница, соответствующая URL-адресу, не может быть найдена.
основные зависимости
Как реализован Router при таком количестве сценариев? На самом деле, это зависит от основногоpath-to-regexpметод.
var pathToRegexp = require('path-to-regexp')
// pathToRegexp(path, keys, options)
// 示例
var keys = []
var re = pathToRegexp('/foo/:bar', keys)
// re = /^\/foo\/([^\/]+?)\/?$/i
// keys = [{ name: 'bar', prefix: '/', delimiter: '/', optional: false, repeat: false, pattern: '[^\\/]+?' }]
разделитель: разделитель повторяющихся параметров, по умолчанию '/', настраиваемый
Некоторые другие распространенные подстановочные знаки маршрутизации:
-
необязательные параметры
-
* соответствует 0 или более раз
-
+ соответствует 1 или более раз
Если вы забыли написать имя параметра и написали только правила маршрутизации, например, в следующем коде/:foo
Следующие параметры:
var re = pathToRegexp('/:foo/(.*)', keys)
// 匹配除“\n”之外的任何字符
// keys = [{ name: 'foo', ... }, { name: 0, ...}]
re.exec('/test/route')
//=> ['/test/route', 'test', 'route']
Он также правильно анализирует, за исключением того, что внутри обработчика метода имена безымянных параметров заменяются индексами массива.
получить параметры маршрутизации
Параметры пути можно передать черезthis.props.match
Получать
Например:
// url 为 /book/:pageType(edit|detail|add)
const { match } = this.props;
const { pageType } = match.params;
Так как есть #, то все, что после #, будет считаться частью хэша, и window.location.search не сможет получить параметры со знаком вопроса.
Например:Ааа. Yaohan.com/book-center…
Затем в React-Router параметры со знаком вопроса можно передать черезthis.props.location
(Официальная реклама на стене 👍) Получите это. Личное понимание заключается в том, что React-Router выполнил за нас обработку и проанализировал инкапсуляцию с помощью маршрутизации и хеш-значения (window.location.hash).
Например:
// url 为 /book?pageType=edit
const { location } = this.props;
const searchParams = location.search; // ?pageType=edit
Чтобы распечатать найденный параметр реквизита,this.props.history.location
Также можно использовать параметр со знаком вопроса, но это не рекомендуется, поскольку жизненный цикл React (componentWillReceiveProps, componentDidUpdate) может сделать его ненадежным. (По причинам см.:blog.CSDN.net/1210/art…
В ранней версии React-Router 2.0 для получения параметров можно было использовать location.query.pageType, но в версии 4.0 это было удалено (некоторые люди думают, что параметры запроса не являются частью URL-адреса, а некоторые думают, что существует много сторонние библиотеки, которые оставлены разработчикам Лучше разбирать самому, на этом обсуждении есть Issue, можете сами достать, если интересно 😊GitHub.com/реагировать поезд я…
Для случая C из сценария 1 в предыдущем разделе при запросе скрытого метода параметра (взятого из состояния) вthis.props.location.state
Вы можете получить его (не рекомендуется, не рекомендуется, не рекомендуется, обновление не будет ~)
Switch
<div>
<Route
path="/router/:type"
render={() => <div>影像</div>}
/>
<Route
path="/router/book"
render={() => <div>图书</div>}
/>
</div>
если<Route />
Выложен плиткой (сdiv
обертка, потому что под маршрутизатором может быть только один элемент), введите/router/book
И изображение, и книга будут рендериться, если вы хотите рендерить только одну из них, вам нужно переключить
<Switch>
<Route
path="/router/:type"
render={() => <div>影像</div>}
/>
<Route
path="/router/book"
render={() => <div>图书</div>}
/>
</Switch>
Переключение означает точную визуализацию компонентов по разным маршрутам в соответствии с разными путями. Однако после добавления Switch правила сопоставления маршрутов выполняются сверху вниз. Так что будьте осторожны при его использовании.
В приведенном выше коде пользователь получает доступ/router/book
, второе правило маршрутизации (не показывает «Книги») не сработает, поскольку оно будет соответствовать/router/:type
это правило. Поэтому пути с параметрами обычно пишутся внизу правил маршрутизации.
Основы маршрутизации
Что делает маршрутизация: управляет изменениями URL, меняет адрес в браузере.
Что делает маршрутизатор: когда URL-адрес изменяется, он запускает рендеринг и отображает соответствующий компонент.
Существует два типа URL-адресов, один без # и один с #, что соответствует режиму просмотра и режиму хеширования соответственно.
В обычных одностраничных приложениях есть два способа изменить URL-адрес без перезагрузки страницы:
Case 1(Будет запущено событие прослушивания маршрута): Нажмите вперед, назад или вызовите history.back(), history.forward().
Case 2(Событие прослушивателя маршрута не будет запущено): вызовите history.push() и history.replace() в компоненте
Так ссылайся«Анализ исходного кода» На этот раз я полностью понимаю принцип маршрутизации React-Router.В этой статье сделаны следующие выводы для двух описанных выше случаев и двух режимов, соответствующих этим двум случаям.
Источник изображения: «Анализ исходного кода». На этот раз я полностью понимаю принцип маршрутизации React-Router.
Режим браузера
Case 1:
При изменении URL-адреса запускается событие прослушивателя маршрута.popstate
, затем функция обратного вызова, которая прослушивает событиеhandlePopState
История триггеров в обратном вызовеsetState
метод для создания нового объекта местоположения. Изменения состояния, уведомите компонент маршрутизатора об обновленииlocation
И передайте его через контекст контекста, сопоставьте соответствующий компонент маршрута и, наконец,<Route />
Компонент извлекает соответствующий контент, передает его на страницу рендеринга и рендерит обновление.
/* 简化版的 handlePopState (监听事件的回调) */
const handlePopState = (event)=>{
/* 获取当前location对象 */
const location = getDOMLocation(event.state)
const action = 'POP'
/* transitionManager 处理路由转换 */
transitionManager.confirmTransitionTo(location, action, getUserConfirmation, (ok) => {
if (ok) {
setState({ action, location })
} else {
revertPop(location)
}
})
}
Case 2:Возьмем, к примеру, history.push. Сначала создайте новый на основе пути, по которому вы хотите перейти.location
объект, а затем передатьwindow.history.pushState
(API предоставляется H5) Метод изменяет текущий маршрут браузера (т. е. текущий URL-адрес) и, наконец, проходитsetState
Метод уведомляет маршрутизатор, запуская обновление компонента.
const push = (path, state) => {
const action = 'PUSH'
/* 创建location对象 */
const location = createLocation(path, state, createKey(), history.location)
/* 确定是否能进行路由转换 */
transitionManager.confirmTransitionTo(location, action, getUserConfirmation, (ok) => {
... // 此处省略部分代码
const href = createHref(location)
const { key, state } = location
if (canUseHistory) {
/* 改变 url */
globalHistory.pushState({ key, state }, null, href)
if (forceRefresh) {
window.location.href = href
} else {
/* 改变 react-router location对象, 创建更新环境 */
setState({ action, location })
}
} else {
window.location.href = href
}
})
}
Хэш-режим
Case 1:
Добавьте мониторинг, когда хэш URL-адреса изменится, инициируйте обратный вызов, зарегистрированный hashChange, и выполните аналогичные операции в обратном вызове для отображения другого контента.
window.addEventListener('hashchange',function(e){
/* 监听改变 */
})
Case 2:
history.push
низкоуровневый вызовwindow.location.hash
изменить маршрут.history.replace
Нижний слой - позвонитьwindow.location.replace
Измените маршрут. Затем setState уведомляет об изменении.
Согласно некоторым справочным материалам, по соображениям совместимости (метод H5 не совместим с IE10 и ниже) система маршрутизации использует режим Hash как метод по умолчанию для создания объекта History. (Если есть сомнения, поправьте меня~)
Dva/Router
В реальном проекте обнаружено, что Link и Route взяты изdva/router
Завезен из Китая, так что же здесь Двава делала?
Ответ: Кажется, что особой обработки нет. Dva сделала инкапсуляцию верхнего уровня на React-Router, которая будет выводить по умолчаниюReact-Routerинтерфейс.
Некоторые вещи, которые мы сделали с Router
Case 1:
В каталоге src кода проекта, независимо от того, сколько там папок, маршруты обычно хранятся в одном и том же файле router.js.Однако, когда страниц становится слишком много, содержимое файла становится все длиннее и длиннее, который нелегко найти и изменить.
Таким образом, мы можем внести небольшие изменения в каждую папку в src, создать собственные файлы конфигурации маршрутизации для управления собственной маршрутизацией. Но в этом случае React-Router не распознается, поэтому мы написали плагин и поместили его в Webpack, цель — суммировать маршруты в каждой папке и сгенерировать файл router-config.js. После этого разберите содержимое файла на соответствующий контент, требуемый компонентом. С реализацией плагина можно ознакомиться в другой статье команды:Практическое руководство по началу работы с плагином Webpack.
Case 2:
Хотя хеш-режим маршрутизации имеет хорошую совместимость, есть некоторые проблемы:
- Он не очень дружелюбен к SEO и фронтенд-встраиванию, и пути разграничить непросто.
- Если исходная страница имеет якоря, при использовании режима хеширования будут возникать конфликты.
Таким образом, компания сделала хеш-маршрут преобразованием браузерного маршрута.
Если исходная ссылка:Ааа. Yaohan.com/book-center…
План трансформации таков:
Удалите #, добавив следующий код конфигурации
import createHistory from 'history/createBrowserHistroy';
const app = dva({
history: createHistory({
basename: '/book-center',
}),
onError,
});
В то же время, чтобы избежать 404 при посещении пользователями старой страницы, фронтенду необходимо настроить перенаправление в Redirect и настроить переадресацию старой страницы Hash в Nginx.
Case 3:
Фактически, в реальном проекте мы также рассмотрим различные ситуации, такие как переходы маршрутизации, когда пользователь не авторизован, и переходы маршрутизации, когда страница 404. Следующие случаи и коды предназначены только для справки читателей ~
<Switch>
{
getRoutes(match.path, routerData).map(item =>
(
// 用户未授权处理,AuthorizedRoute 为项目中自己实现的处理组件
<AuthorizedRoute
{...item}
redirectPath="/exception/403"
/>
)
)
}
// 默认跳转页面
<Redirect from="/" exact to="/list" />
// 页面 404 处理
<Route render={props => <NotFound {...props} />} />
</Switch>
Ссылка на ссылку
«Источник решить» на этот раз полностью понять принципы маршрутизатора React-маршрутизатора
анализ правил маршрутизации react-router v4
Решение для двухуровневой динамической маршрутизации
Рекомендуемое чтение
Самая знакомая незнакомка rc-форма
Возможности Vite и частичный анализ исходного кода
Как создать платформу сборки и развертывания, подходящую для вашей команды
работы с открытым исходным кодом
- Zhengcaiyun интерфейсный таблоид
адрес с открытым исходным кодомwww.zoo.team/openweekly/(На главной странице официального сайта таблоида есть группа обмена WeChat)
Карьера
ZooTeam, молодая, увлеченная и творческая команда, связанная с отделом исследований и разработок продукции Zhengcaiyun, базируется в живописном Ханчжоу. В настоящее время в команде более 40 фронтенд-партнеров, средний возраст которых составляет 27 лет, и почти 30% из них — инженеры полного стека, настоящая молодежная штурмовая группа. В состав членов входят «ветераны» солдат из Ali и NetEase, а также первокурсники из Чжэцзянского университета, Университета науки и технологий Китая, Университета Хандянь и других школ. В дополнение к ежедневным деловым связям, команда также проводит технические исследования и фактические боевые действия в области системы материалов, инженерной платформы, строительной платформы, производительности, облачных приложений, анализа и визуализации данных, а также продвигает и внедряет ряд внутренних технологий. Откройте для себя новые горизонты передовых технологических систем.
Если вы хотите измениться, вас забрасывают вещами, и вы надеетесь начать их бросать; если вы хотите измениться, вам сказали, что вам нужно больше идей, но вы не можете сломать игру; если вы хотите изменить , у вас есть возможность добиться этого результата, но вы не нужны; если вы хотите изменить то, чего хотите достичь, вам нужна команда для поддержки, но вам некуда вести людей; если вы хотите изменить установившийся ритм, это будет "5 лет рабочего времени и 3 года стажа работы"; если вы хотите изменить исходный Понимание хорошее, но всегда есть размытие того слоя оконной бумаги.. , Если вы верите в силу веры, верьте, что обычные люди могут достичь необыкновенных вещей, и верьте, что они могут встретить лучшего себя. Если вы хотите участвовать в процессе становления бизнеса и лично способствовать росту фронтенд-команды с глубоким пониманием бизнеса, надежной технической системой, технологиями, создающими ценность, и побочным влиянием, я думаю, что мы должны говорить. В любое время, ожидая, пока вы что-нибудь напишете, отправьте это наZooTeam@cai-inc.com