React Router
1. Маршрутизация
Отличающее преимущество веб-приложения от десктоп это наличие URL, при переходе по которому, пользователь оказывается в определенной части приложения. Так можно сохранить закладку или передать ссылку другому пользователю, при этом ему будет отображен один и тот же интерфейс (за исключением приватных данных).
Маршрутизация (routing) - это не побочный эффект при написании приложения, наоборот, грамотную архитектуру навигации необходимо продумывать в первую очередь.
1.1. Структура URL-строки
Аналогией URL-строки может быть адрес по которому вы проживаете: улица, дом, квартира. У каждого состояния интерфейса должен быть свой адрес, свой URL. То, что видит пользователь, состояние интерфейса, должно быть описано в URL.

https://- протоколmysite.com/- хостbooks/e3q76gm9lzk- путь, то где мы находимся в приложенииe3q76gm9lzk- url-параметр. Параметры бывают динамическими или статическими?- символ начала строки запроса?category=adventure&status=unread - строка запросаcategory=adventure- пара параметр=значение&- символ "И", разделяет параметры строки запроса#comments- якорь (хеш), определяет положение на странице
1.2. История навигации
История навигации - то как мы переходим ссылкам, как переходы хранятся и парсятся. От типа истории зависит метод ее хранения и изменения.
Если вы хотите понять React Router, рекомендуется ознакомиться с HTML5 History API. Более конкретно, c пакетом history, который предоставляет основные функциональные возможности для React Router, позволяя одностраничным приложениям легко добавлять навигацию на стороне клиента.
Существует несколько типов истории.
Browser history - использует HTML5 History API, стандарт управления историей браузера из JavaScript.
Hash history - в старых браузерах не поддерживается HTML5 History API, поэтому для них существует эта реализация.
Memory history - позволяет использовать историю сессии в памяти, вне окна браузера. К примеру для тестирования логики без интерфейса и в средах без DOM, к примеру React Native.
2. React Router
Предоставляет набор компонентов для управления частями URL-строки и отображения различных компонетов в зависимости от текущего ее состояния. Разбит на пакеты для различных платформ, нас интересует react-router-dom.
В React Router есть три типа компонентов: компонент маршрутизатора, компоненты согласования маршрутов и компоненты навигации.
2.1. BrowserRouter
В основе каждого одностраничного приложения стоит маршрутизатор. Компонент <BrowserRouter> создает раутер и объект history, чтобы синхронизировать интерфейс с URL-адресом. Используя контекст, передает данные о текущем URL всему поддереву компонентов.
2.2. Route
Компонент позволяющий связать определенный URL и компонент для рендера. Его задача заключается в том, чтобы отобразить некоторый интерфес, когда location.pathname соответствует значению пропа path. Компонент <Route> можно использовать в любом месте где необходимо рендерить контент на основе текущего URL.
Согласование маршрута выполняется путем сопоставления пропа path и текущего значения location.pathname. Если значение location.pathname начинается на указанный путь в path, <Route> отрендерит указанный компонент, в противном случае вернет null.
Когда location.pathname начинается на '/about', первый и третий рауты отрендерят null, а второй отрендерит компонент <About>.
Проп
exactуказывает на необходимость точного совпаденияpathиlocation.pathname<Route>без указанногоpathвсегда рендерит компонент
2.2.1. Проп component
Используется когда компонент необходимо отрендерить без передачи дополнительных пропсов. Стандартные пропсы match, location и history будут переданы компоненту автоматически.
Для создания компонента используется React.createElement(), это означает, что если вместо ссылки на компонент будет передана анонимная функция, для каждого ре-рендера будет создан новый компонент. Это приведет к размонтированию существующего компонента, созданию и монтированию нового на каждом рендере, вместо обновления существующего компонента.
2.2.2. Проп render
Позволяет использовать инлайн-функцию вместо компонента без нежелательного эффекта ре-рендера как в случае с component. Используется тогда, когда компоненту необходимо передать дополнительные пропсы, кроме тех что передает <Route>.
2.3. Switch
Группирует и отображает первый дочерний маршрут, path которого соответствует текущему location.pathname, игнорруя все последующие.
2.4. Redirect
Позволяет декларативно отрендерить компонент который во время маунта перенаправит пользователя по указанному маршруту. Под капотом использует императивный интерфейс history.
По умолчанию подменяет текущую запись в истории, для того чтобы добавить новую запись на верх стека можно передать проп
push.Вместо строки, проп
toможет принимать полноценный объект форматаlocation.
2.5. Link и NavLink
Для создания навигации нельзя использовать обычный HTML-тег <a href="/about">. При клике, вместо того чтобы изменить URL на текущей странице, и позволить раутеру выполнить навигацию на стороне клиента, браузер выполнит GET-запрос и обновит страницу, а это не то, что нам нужно.
Компоненты <Link> и <NavLink> используются для создания ссылок. Они рендерят HTML-тег <a>, но с расширенным функционалом клика, используя возможности объекта history по замене URL.
Проп to можно передавать в виде строки описывающей href будущей ссылки, или как объект location со следующими (необязательными) свойствами:
pathname- строка, путь для ссылки.search- строковое представление параметров запроса.hash- хэш для добавления в конец URL.state- объект, который будет записан вlocation.stateпосле перехода по ссылке.
Компонент <NavLink> отличается от <Link> только тем, что может иметь дополнительные стили, если текущий URL совпадает со значением пропа to.
activeClassName- строка классов для объеденения сclassNameкогда элемент активен.activeStyle- объект инлайн стилей для добавления к элементу когда он активен.exact- когдаtrue, активные классы/стили будут применяться только в том случае, если местоположение точно совпадает со значением пропаto.
2.6. Route props
Компоненту отрендеренному через <Route> будет передано несколько специальных пропсов хранящих много полезной информации.
match— объект с информацией о том как совпалиpathиlocation.pathnamelocation- объект хранящий информацию о текущем URLhistory- объект истории, созданный самим раутером
2.6.1. Проп match
Объект, хранит информацию о том, как path совпал с location.pathname. Содержит следующие свойства.
params- объект парключ:значение, соответствующих динамическим параметрам URL.isExact- указыват на точное соотвествиеpathиlocation.pathname.path- паттерн пути на который замачился<Route>. Используется для создания вложенных маршрутов.url- совпавшая часть URL-адреса. Используется для создания вложенной навигации.
2.6.2. Проп location
Объект, свойства которого описывают текущее местоположение, путь куда будет произведен переход или откуда пришли на текущий маршрут. Можно использовать в том числе для проверки в componentDidUpdate изменился ли текущий URL.
2.6.3. Проп history
Объект истории со свойствами и методами для программной навигации. Используется для перенаправлений.
history.push(path [, state])- добавляет новую запись на стек записей истории.history.replace(path [, state])- подменяет текущую запись на новую на стеке записей истории.
3. Строка запроса
В строке запроса можно указывать дополнительную информацию о текущем маршруте. Например, если мы просматриваем страницу новостных статей, маршрут может выглядеть так.
Если есть категории выбора статей по жанру и времени издания, храним выбранные опции в строке запроса.
Строка запроса содержит 2 параметра: название категории и порядок сортировки статей. При переходе по такому маршруту, можно сделать HTTP-запрос на бэкенд, получив только статьи необходимой категории, и отсортировать их по полю даты издания.
Текущее значение строки запроса хранится в пропе location.
3.1. Извлечение параметров
Чтобы получить значения параметров, можно использовать возможности нативного класса URLSearchParams, а также библиотеки qs или query-string. Любой метод позволит сделать парс строки запроса и получить объект с парами ключ:значение.
3.2. Изменение параметров
Допустим, для выбора категории статей используется <select>. При выборе опции необходимо обновлять URL используя метод history.push() для добавления новой записи в журнал истории.
Берем текущее значение location.pathname и обновляем search.
3.3. Отслеживание изменений
Если меняется строка запроса, компоненту пробрасываются новые пропсы, и в методе componentDidUpdate() можно проверить изменилась ли категория и порядок сортировки. Если изменились, делаем HTTP-запрос или сортируем текущие статьи.
4. Редиректы
Перенаправления это удобный инструмент навигации пользователя между маршрутами приложения. Для их реализации используется компонент <Redirect> или методы history.push() и history.replace().
4.1. Проп history
Важно знать раличие методов push и replace.
history.push()- добавит новую запись в журнал истории, пользователь может вернуться на тот маршрут с которого пришел.history.replace()- перезапишет текущую запись в журнале истории затерев текущую, пользователь не сможет вернутся на маршрут с которого пришел.
Продолжим работать со статьями. При рендере раута /articles есть категории статей, но при первом рендере маршрута еще нет строки запроса с параметром category. Именно поэтому необходимо сделать редирект, при этом перезаписав текущую страницу истории, чтобы пользователь не мог вернуться на страницу без параметров запроса.
4.2. Свойство location.state
Позволяет передавать кастомные данные между маршрутами. Например список статей это ссылки, при клике в ссылку переходим на новый маршрут - страницу статьи.
Тогда, если пользователь пришел с https://app.com/articles?category=sports, и захочет вернуться на сраницу всех статей, нажав стрелку "Обратно", он попадет куда надо. Но что если необходимо реализовать кнопку "Обратно к статьям" в интерфейсе приложения, как узнать откуда мы пришли?
Каждую статью сделаем ссылкой, добавив в свойство state информацию о текущем маршруте.
Тогда в компоненте статьи можем получить эту информацию и при клике на кнопку "Обратно к статьям" перенаправить пользователя на предыдущий маршрут.
Нужно учитывать ситуацию когда пользователь перешел на страницу статьи по сохраненный ссылке, и в текущей сессии не был на странице всех статей. В свойстве location.state не будет объекта, и попытка доступа к state.from приведет к ошибке выполнения скрипта.
Поэтому необходимо проверить location.state. Если state есть - перенаправляем пользователя туда, откуда он пришел. Если state нет - перенаправляем на /articles, при этом параметр category назначаем по свойству статьи (если в объекте статьи есть такое свойство).
Last updated
Was this helpful?