Простой туториал React Router v4

React Router v4 — это переработанный вариант популярного React дополнения. Зависимые от платформы конфигурации роутов из прошлой версии были удалены и теперь всё является простыми компонентами.
Этот туториал покрывает всё что вам нужно для создания веб-сайтов с React Router. Мы будем создавать сайт для локальной спортивной команды.
Хочешь посмотреть демку?
Установка
React Router v4 был разбит на 3 пакета:
react-router предоставляет базовые функции и компоненты для работы в двух окружениях(Браузере и react-native)
Мы будем создавать сайт который будет отображаться в браузере, поэтому нам следует использовать react-router-dom . react-router-dom экспортирует из react-router все функции поэтому нам нужно установить только react-router-dom .
Router
При старте проекта вам нужно определить какой тип роутера использовать. Для браузерных проектов есть BrowserRouter и HashRouter компоненты. BrowserRouter — следует использовать когда вы обрабатываете на сервере динамические запросы, а HashRouter используйте когда у вас статический веб сайт.
Обычно предпочтительнее использовать BrowserRouter , но если ваш сайт расположен на статическом сервере(от перев. как github pages), то использовать HashRouter это хорошее решение проблемы.
Наш проект предполагает использование бекенда поэтому мы будем использовать BrowserRouter .
История — History
Каждый Router создает объект history который хранит путь к текущему location[1] и перерисовывает интерфейс сайта когда происходят какие то изменения пути.
Остальные функции предоставляемые в React Router полагаются на доступность объекта history через context, поэтому они должны рендериться внутри компонента Router.
Заметка: Компоненты React Router не имеющие в качестве предка компонент Router не будут работать, так как не будет доступен context.
Рендеринг Router
Компонент Router ожидает только один элемент в качестве дочернего. Что бы работать в рамках этого условия, удобно создать компонент <App/> который рендерить всё ваше приложение(это так же важно для серверного рендеринга).
App компонент
Наше приложение начинается с <App/> компонента который мы разделим на две части. <Header/> который будет содержать навигационные ссылки и <Main/> который будет содержать контент роутов.
Routes
<Route/> компонент это главный строительный блок React Router’а. В том случае если вам нужно рендерить элемент в зависимости от pathname URL’ов, то следует использовать компонент <Route/>
Path — путь
<Route /> принимает path в виде prop который описывает определенный путь и сопоставляется с location.pathname.
В примере выше <Route/> сопоставляет location.pathname который начинается с /roster[2]. Когда текущий location.pathname сопоставляется положительно с prop path то компонент будет отрендерен, а если мы не можем их сопоставить, то Route ничего не рендерит[3].
Заметка: Когда речь идет о пути React Router думает только о пути без домена. Это значит, что в адресе:
React Router будет видеть только /my-projects/one
Сопоставление пути
npm пакет path-to-regexp компилирует prop path в регулярное выражение и сопоставляет его против location.pathname. Строки path имеют более сложные опции форматирования чем объясняются здесь. Вы можете почитать документацию.
Когда пути сопоставляются создается объект match который содержит свойства:
- url — сопоставляемая часть текущего location.pathname
- path — путь в компоненте Route
- isExact — path в Route === location.pathname
- params — объект содержит значения из path которые возвращает модуль path-to-regexp
Заметка: path в Route должен быть абсолютным[4].
Создание наших роутов
Компонент Route может быть в любом месте в роутере, но иногда нужно определять, что рендерить в одно и тоже место. В таком случае следует использовать компонент группирования Route’ов — <Switch/> . <Switch/> итеративно проходит по дочерним компонентам и рендерит только первый который подходит под location.pathname.
У нашего веб-сайта пути которые мы хотим сопоставлять такие:
- / — Главная страница
- /roster — Страница команд
- /roster/:number — Страница профиля игрока по номеру
- /schedule — Расписание игр команды
Что делает рендер компонента Route?
У Route есть 3 props’a которые описывают каким образом выполнить рендер сопоставляя prop path с location.pathname и только один из prop должен быть представлен в Route:
- component — React компонент. Когда роут удовлетворяется сопоставление в path, то он возвращает переданный component (используя функцию React.createElement).
- render — функция которая должна вернуть элемент React. Будет вызвана когда удовлетворится сопоставление в path. Render довольно похож на component, но используется для inline рендеринга и подстановки необходимых для элемента props[5].
- children — в отличие от предыдущих двух props children будет всегда отображаться независимо от того сопоставляется ли path или нет.
В типичных ситуациях следует использовать component или render. Children prop может быть использован, но лучше ничего не делать если path не совпадает с location.pathname.
Элементу отрендеренному Route будет передано несколько props. match — объект сопоставления path с location.pathname , location объект[6] и history объект(созданный самим роутом)[7].
Main
Сейчас мы опишем основную структуру роутера. Нам просто нужно отобразить наши маршруты. Для нашего приложения мы будем использовать компонент <Switch/> и компонент <Route/> внутри нашего компонента <Main/> который поместит сгенерированный HTML удовлетворяющий сопоставлению path внутри.
<Main/> DOM узла(node)
Заметка: Route для главной страницы содержит prop exact , благодаря которому пути сравниваются строго.
Унаследованные роуты
Профиль игрока /roster/:number не включен в <Switch/> . Вместо этого он будет рендериться компонентом <Roster/> который рендериться всякий раз когда путь начинается с /roster .
В компоненте Roster мы создадим компоненты для двух путей:
- /roster — с prop exact
- /roster/:number — этот route использует параметр пути, который будет отловлен после /roster
Может быть полезным группирование роутов которые имеют общие компоненты, что позволяет упростить родительские маршруты и позволяет отображать контент который относиться к нескольким роутам.
К примеру <Roster/> может быть отрендерен с заголовком который будет отображаться во всех роутах которые начинаются с /roster .
Параметры в path
Иногда нам требуется использовать переменные для получения какой либо информации. К примеру, роут профиля игрока, где нам требуется получить номер игрока. Мы сделали это добавив параметр в prop path .
:number часть строки в /roster/:number означает, что часть path после /roster/ будет получена в виде переменной и сохранится в match.params.number . К примеру путь /roster/6 сгенерирует следующий объект с параметрами:
Компонент <Player/> будет использовать props.match.params для получения нужной информации которую следует отрендерить.
Заметка: Вы можете больше изучить о параметрах в путях в пакете path-to-regexp
Наряду с компонентом <Player/> наш веб-сайт использует и другие как <FullRoster/> , <Schedule/> и <Home/> .
Ссылки
Последний штрих, наш сайт нуждается в навигации между страницами. Если мы создадим обычные ссылки то страница будет перезагружаться. React Router решает эту проблему компонентом <Link/> который предотвращает перезагрузку. Когда мы кликаем на <Link/> он обновляет URL и React Router рендерит нужный компонент без обновления страницы.
<Link/> использует prop to для описания URL куда следует перейти. Prop to может быть строкой или location объектом (который состоит из pathname, search, hash, state свойств). Если это строка то она конвертируется в location объект.
Заметка: Пути в компонентах <Link/> должны быть абсолютными[4].
Работающий пример
Весь код нашего веб сайта доступен по этому адресу на codepen.
Route готов!
Надеюсь теперь вы готовы погрузиться в изучение деталей маршрутизации веб приложений.
Мы использовали самые основные компоненты которые вам понадобятся при создании собственных веб приложений ( <BrowserRouter.>, <Route.>, and <Link.> ), но есть еще несколько компонентов и props которые здесь не рассмотрены. К счастью у React Router есть прекрасная документация где вы можете найти более подробное объяснение компонентов и props. Так же в документации предоставляются работающие примеры с исходным кодом.
Пояснения
[1] — Объект location описывает разные части URL’a
[2] — Вы можете использовать компонент <Route/> без path. Это полезно для передачи методов и переменных которые храняться в context .
[3] — Если вы используете prop children то route будет отрендерен даже если path и location.pathname не совпадают.
[4] — Сейчас ведется работа над относительными путями в <Route/> и <Link/> . Относительные <Link/> более сложные чем могут показаться, они должны быть разрешены используя свой родительский объект match , а не текущий URL.
[5] — Это stateless компонент. Внутри есть большая разница между render и component . Component использует React.createElement для создания компонента, в то время как render используется как функция. Если бы вы определили inline функцию и передали через нее props то это было бы намного медленнее чем с использованием функции render .
[6] — Компоненты <Route/> и <Switch/> могут оба использовать prop location. Это позволяет сопоставлять их с path, который фактически отличается от текущего URL’а.
[7] — Так же передают staticContext , но он полезен только при рендере на сервере.
Туториал по использованию React Router v4
React Router v4 – полностью переписанная версия распространенного пакета для React. В прошлых версиях React Router использовались такие конфигурации и псевдокомпоненты, что его было тяжело понять. В v4 же содержатся только компоненты.
В этом уроке мы будем создавать веб-сайт (single page application) для местной спортивной команды. Мы разберем основы, необходимые для запуска веб-сайта и роутинга. В статье будут описаны следующие пункты:
- Выбор роутера;
- Создание маршрутов;
- Навигация по маршрутам с помощью ссылок.
Хотите просто посмотреть на то, как работает веб-сайт? Вот. Никакого замысловатого дизайна, только простой и функциональный сайт.
Установка
React Router разделен на 3 пакета: react-router , react-router-native и react-router-dom .
Вам практически никогда не придется устанавливать react-router напрямую. Этот пакет содержит основные компоненты для маршрутизации и функции для созданных в React Router приложений. Остальные пакеты предоставляют специфические для среды (браузер, React Native) компоненты и заново экспортируют все экспорты react-router .
Мы создаем веб-сайт (то, что будет запускаться в браузерах), так что нам нужно будет установить react-router-dom :
Router
При запуске нового проекта необходимо определить, какой тип роутера нужно использовать. Для проектов на основе браузера есть компоненты <BrowserRouter> и <HashRouter> . <BrowserRouter> следует использовать, когда у вас есть сервер, который будет обрабатывать динамические запросы (т. е. знает, как реагировать на любой возможный URI), тогда как <HashRouter> стоит применять для статических веб-сайтов (где сервер может отвечать только на запросы файлов, о которых он знает).
Обычно предпочтительнее использовать <BrowserRouter> . Если ваш веб-сайт будет размещен на сервере, который обслуживает только статические файлы, то <HashRouter> — хороший вариант.
Предположим, что в нашем проекте веб-сайт будет поддерживаться динамическим сервером, поэтому выберем компонент роутера <BrowserRouter> .
History
Каждый роутер создает объект history , который он использует для отслеживания текущего местоположения и повторного рендеринга веб-сайта при изменении местоположения. Другие компоненты, предоставляемые React Router, опираются на то, что объект history доступен через контекст React. Они должны отображаться как потомки компонента роутера. Компонент роутера React, предком которого не является сам роутер, не сможет работать.
Обработка <Router>
Компоненты роутера ожидают получить только один дочерний элемент. Чтобы работать в рамках этого ограничения, стоит создать компонент <App> , который отображает остальную часть приложения. Отделение приложения от маршрутизатора также полезно для рендеринга сервера, поскольку вы можете повторно использовать <App> на сервере при переключении роутера на <MemoryRouter> .
Так как мы выбрали роутер, можно начинать обработку single page application, т. е. самого сайта.
Приложение определяется в компоненте <App> . Чтобы упростить ситуацию, мы разделим наше приложение на 2 части. Компонент <Header> будет содержать ссылки для навигации по сайту. Компонент <Main> — то, где будет отображаться остальная часть контента.
Сначала мы определим контент в компоненте <Main> . Здесь пройдет обработка маршрутов.
Routes
Компонент <Route> является основным блоком роутера React. Если вы хотите обрабатывать только контент, основанный на полном имени ссылки, нужно использовать элемент <Route> .
Path
<Route> ожидает свойство path. Оно представляет собой строку, описывающую имя пути, которому соответствует маршрут. Например, <Route path=’/roster’/> должен соответствовать пути, начинающемуся с /roster . Когда путь к текущему местоположению совпадает с path, маршрут будет производить рендер элемента React. Если path не совпадает, маршрут не будет ничего отображать.
Что касается подбора маршрутов, роутер React заботит только путь к месту. Это означает, что с учетом URL:
Роутер React пытается найти соответствующий маршрут только для /my-projects-one .
Подбор маршрутов
Роутер React использует пакет path-to-regexp для определения соответствия path элемента и текущего местоположения. Пакет компилирует строку path в регулярное выражение, которое сопоставляется с путевым именем. Строки path имеют более продвинутые параметры форматирования, чем будет описано здесь .
Когда path маршрута находит совпадение, создается соответствующий объект со следующими свойствами:
- url – совпавшая часть путевого имени;
- path – путь маршрута;
- isExact – path === pathname;
- params – объект, содержащий значения из путевого имени, которые были захвачены path-to-regexp.
Вы можете использовать этот тестер маршрутов, чтобы разобраться с сопоставлением маршрутов и URL.
Создание маршрутов
<Route> могут быть созданы в любом месте внутри роутера, но чаще всего обрабатывать их стоит в одном и том же месте. Можно использовать компонент <Switch> для группировки <Route> . <Switch> будет перебирать свои дочерние элементы (маршруты) и отображать только первый, соответствующий текущему пути.
Для этого сайта мы хотим найти соответствия следующим путям:
- / — домашняя страница;
- /roster — список команды;
- /roster:number — профиль игрока с использованием его номера;
- /schedule — график игр команды.
Чтобы найти соответствия путям в нашем приложении, необходимо создать элемент <Route> с указанием path, которому мы хотим соответствовать.
Что обрабатывает <Route>?
У маршрутов есть 3 свойства, которые можно использовать для определения того, что должно быть обработано среди соответствий. Элемент <Route> должен содержать только 1 свойство.
- component – компонент React. Когда маршрут со свойством component находит соответствие, маршрут вернет новый элемент, тип которого предоставляется компонентом React (он создается с использованием React.createElement);
- render – функция, которая возвращает элемент React. Она будет вызываться при нахождении соответствия. Свойство похоже на component, но полезно для встроенного рендеринга и передачи дополнительных свойств элементу;
- children – функция, которая возвращает элемент React. В отличие от предыдущих 2 свойств, она всегда будет отображаться независимо от того, соответствует ли путь маршрута текущему местоположению.
Как правило, следует использовать либо component, либо render. Свойство children иногда может быть полезно. Обычно не стоит что-либо обрабатывать при отсутствии совпадений. У нас нет никаких дополнительных свойств для передачи компонентам, поэтому каждый из наших <Route> будет использовать свойство component.
Элементу, обработанному <Route> , будет передан ряд свойств. Это будут объекты match , location , history (тот, что был создан роутером).
<Main>
Раз уж мы разобрались с корневой структурой маршрутов, нам просто нужно обработать их. Для этого приложения вида single page application мы будем отображать <Switch> и <Route> внутри компонента <Main> , который поместит HTML, сгенерированный с помощью соответствующего маршрута, в DOM-узел <main> .
Вложенные маршруты
Маршрут профиля игрока /roster/:number не входит в вышеописанный <Switch> . Вместо этого он будет обработан компонентом <Roster> , рендер которого происходит всякий раз, когда путь начинается с /roster .
В компоненте <Roster> будет осуществляться обработка 2 путей:
/roster . Соответствие ему может быть найдено только в том случае, если имя пути точно является /roster , поэтому мы также должны присвоить этому элементу маршрута свойство exact;
/roster/:number . Этот маршрут применяет параметр path, чтобы захватить часть имени пути, которая идет после /roster .
Может быть полезно сгруппировать маршруты с общим префиксом в одном компоненте. Это позволяет упростить родительские маршруты и дает возможность отображать содержимое, общее для всех маршрутов с одинаковым префиксом.
Например, <Roster> может обрабатывать заголовок, который будет отображаться для всех маршрутов, путь которых начинается с /roster .
Параметры пути
Иногда в пути есть переменные, которые хочется использовать. Например, с помощью маршрута профиля игрока можно получить номер игрока. Мы можем сделать это, добавив параметры пути в строку path маршрута.
Часть :number пути /roster/:number означает, что часть имени пути, которая следует после /roster/ , будет захвачена и сохранена как match.params.number . Например, pathname /roster/6 сгенерирует объект параметров:
Компонент <Player> может использовать объект props.match.param для определения данных игрока, которые должны быть обработаны.
Помимо компонента <Player> , наш веб-сайт также включает компоненты <FullRoster> , <Schedule> и <Home> .
Ссылки
Наконец, приложение должно получить метод навигации между страницами. Если бы мы создавали ссылки с использованием якорных элементов, нажатие на них приводило бы к перезагрузке всей страницы. Роутер React предоставляет компонент <Link> для предотвращения таких ситуаций. При щелчке по <Link> URL-адрес будет обновлен, а отображаемый контент изменится без перезагрузки страницы.
<Link> использует свойство to для описания местоположения, к которому нужно совершить переход. Это может быть либо строка, либо объект местоположения (он должен содержать комбинацию свойств pathname, hash, state и search). Если это будет строка, она будет преобразована в объект местоположения.
Работающий пример
Если вы не хотите возвращаться к началу статьи, то с демонстрацией этого проекта можно ознакомиться на CodeSandbox .
Надеемся, теперь вы готовы создавать собственный веб-сайт.
Мы рассмотрели наиболее важные компоненты, которые пригодятся при создании веб-сайта ( <BrowserRouter> , <Route> , <Link> ). И все же существует множество компонентов, которые мы не обсудили, а также свойств рассмотренных компонентов.