Некоторые основы маршрутизатора в React

внешний интерфейс JavaScript React.js
Некоторые основы маршрутизатора в React

Это 109-я оригинальная статья без воды.Если вы хотите получить больше оригинальных статей, выполните поиск в официальном аккаунте и подпишитесь на нас~ Эта статья была впервые опубликована в блоге Zhengcaiyun:Некоторые основы маршрутизатора в React

鱼鱼.png

предисловие

Каждый раз, когда разрабатывается новая страница, неизбежно создание нового 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:

Хотя хеш-режим маршрутизации имеет хорошую совместимость, есть некоторые проблемы:

  1. Он не очень дружелюбен к SEO и фронтенд-встраиванию, и пути разграничить непросто.
  2. Если исходная страница имеет якоря, при использовании режима хеширования будут возникать конфликты.

Таким образом, компания сделала хеш-маршрут преобразованием браузерного маршрута.

Если исходная ссылка:Ааа. 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 и частичный анализ исходного кода

Как я использую git на работе

Как создать платформу сборки и развертывания, подходящую для вашей команды

работы с открытым исходным кодом

  • Zhengcaiyun интерфейсный таблоид

адрес с открытым исходным кодомwww.zoo.team/openweekly/(На главной странице официального сайта таблоида есть группа обмена WeChat)

Карьера

ZooTeam, молодая, увлеченная и творческая команда, связанная с отделом исследований и разработок продукции Zhengcaiyun, базируется в живописном Ханчжоу. В настоящее время в команде более 40 фронтенд-партнеров, средний возраст которых составляет 27 лет, и почти 30% из них — инженеры полного стека, настоящая молодежная штурмовая группа. В состав членов входят «ветераны» солдат из Ali и NetEase, а также первокурсники из Чжэцзянского университета, Университета науки и технологий Китая, Университета Хандянь и других школ. В дополнение к ежедневным деловым связям, команда также проводит технические исследования и фактические боевые действия в области системы материалов, инженерной платформы, строительной платформы, производительности, облачных приложений, анализа и визуализации данных, а также продвигает и внедряет ряд внутренних технологий. Откройте для себя новые горизонты передовых технологических систем.

Если вы хотите измениться, вас забрасывают вещами, и вы надеетесь начать их бросать; если вы хотите измениться, вам сказали, что вам нужно больше идей, но вы не можете сломать игру; если вы хотите изменить , у вас есть возможность добиться этого результата, но вы не нужны; если вы хотите изменить то, чего хотите достичь, вам нужна команда для поддержки, но вам некуда вести людей; если вы хотите изменить установившийся ритм, это будет "5 лет рабочего времени и 3 года стажа работы"; если вы хотите изменить исходный Понимание хорошее, но всегда есть размытие того слоя оконной бумаги.. , Если вы верите в силу веры, верьте, что обычные люди могут достичь необыкновенных вещей, и верьте, что они могут встретить лучшего себя. Если вы хотите участвовать в процессе становления бизнеса и лично способствовать росту фронтенд-команды с глубоким пониманием бизнеса, надежной технической системой, технологиями, создающими ценность, и побочным влиянием, я думаю, что мы должны говорить. В любое время, ожидая, пока вы что-нибудь напишете, отправьте это наZooTeam@cai-inc.com