Обзор функций¶
Маршрутизация на стороне клиента¶
React Router обеспечивает "маршрутизацию на стороне клиента".
На традиционных веб-сайтах браузер запрашивает документ с веб-сервера, загружает и оценивает CSS и JavaScript-активы, а также отображает HTML, присланный с сервера. Когда пользователь нажимает на ссылку, процесс начинается заново для новой страницы.
Маршрутизация на стороне клиента позволяет приложению обновлять URL-адрес, полученный при переходе по ссылке, без повторного запроса документа с сервера. Вместо этого приложение может сразу отобразить новый пользовательский интерфейс и выполнить запрос данных с помощью fetch
для обновления страницы новой информацией.
Это позволяет ускорить работу пользователя, поскольку браузеру не нужно запрашивать совершенно новый документ или заново оценивать CSS- и JavaScript-активы для следующей страницы. Кроме того, это обеспечивает более динамичную работу с такими элементами, как анимация.
Маршрутизация на стороне клиента обеспечивается созданием Router
и ссылками/редиректами на страницы с помощью Link
и <Form>
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Вложенные маршруты¶
Вложенная маршрутизация - это общая идея связывания сегментов URL с иерархией компонентов и данными. Вложенные маршруты React Router были вдохновлены системой маршрутизации в Ember.js примерно в 2014 году. Команда Ember поняла, что почти в каждом случае сегменты URL определяют:
- макеты, которые будут отображаться на странице
- зависимости данных от этих макетов.
В React Router эта концепция реализована с помощью API для создания вложенных макетов, связанных с сегментами URL и данными.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
|
Эта визуализация может оказаться полезной.
Динамические сегменты¶
Сегменты URL могут быть динамическими заполнителями, которые анализируются и предоставляются различным apis.
1 |
|
Два сегмента с :
являются динамическими и предоставляются следующим API:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
См:
Ранжированное сопоставление маршрутов¶
При сопоставлении URL с маршрутами React Router ранжирует маршруты по количеству сегментов, статических сегментов, динамических сегментов, сплетов и т.д. и выбирает самое конкретное соответствие.
Например, рассмотрим эти два маршрута:
1 2 |
|
Теперь рассмотрим URL-адрес http://example.com/teams/new
.
Несмотря на то, что технически оба маршрута соответствуют URL (new
может быть :teamId
), интуитивно понятно, что мы хотим выбрать второй маршрут (/teams/new
). Алгоритм согласования React Router тоже это знает.
При использовании ранжированных маршрутов не нужно заботиться об упорядочивании маршрутов.
Активные ссылки¶
Большинство веб-приложений имеют постоянные разделы навигации в верхней части пользовательского интерфейса, в боковой панели, а зачастую и на нескольких уровнях. Стилизация активных элементов навигации, чтобы пользователь знал, где он находится (isActive
) или куда направляется (isPending
) в приложении, легко выполняется с помощью <NavLink>
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Вы также можете useMatch
для любого другого "активного" указания вне ссылок.
1 2 3 4 5 6 |
|
См:
Относительные ссылки¶
Как и HTML <a href>
, <Link to>
и <NavLink to>
могут принимать относительные пути, при этом улучшается поведение с вложенными маршрутами.
Приведем следующую конфигурацию маршрута:
1 2 3 4 5 |
|
Рассмотрим url https://example.com/home/project/123
, который отображает следующую иерархию компонентов маршрута:
1 2 3 |
|
Если <Project />
отображает следующие ссылки, то hrefs
этих ссылок разрешатся следующим образом:
In <Project> @ /home/project/123 | Resolved <a href> |
---|---|
<Link to="abc"> | /home/project/123/abc |
<Link to="."> | /home/project/123 |
<Ссылка на="..."> | /home |
<Ссылка на="..." relative="path"> | /home/project |
Обратите внимание, что первый ..
удаляет оба сегмента маршрута project/:projectId
. По умолчанию ..
в относительных ссылках обходит иерархию маршрутов, а не сегменты URL. Добавление relative="path"
в следующем примере позволяет обходить сегменты пути.
Относительные ссылки всегда относятся к пути маршрута, по которому они предоставлены, а не к полному URL. Это означает, что если пользователь перейдет по ссылке <Link to="abc">
к ссылке <Task />
на URL /home/project/123/abc
, то hrefs в <Project>
не изменится (в отличие от простого <a href>
, что является распространенной проблемой маршрутизаторов на стороне клиента).
Загрузка данных¶
Поскольку сегменты URL обычно связаны с постоянными данными вашего приложения, React Router предоставляет обычные крючки загрузки данных для инициирования загрузки данных во время навигации. В сочетании с вложенными маршрутами все данные для нескольких макетов по определенному URL-адресу могут загружаться параллельно.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Данные предоставляются вашим компонентам через useLoaderData
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Когда пользователь посещает или переходит по ссылке на https://example.com/real-salt-lake/45face3
, все три загрузчика маршрутов будут вызваны и загружены параллельно, до того, как отобразится пользовательский интерфейс для этого URL.
Перенаправления¶
При загрузке или изменении данных часто требуется перенаправить пользователя на другой маршрут.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
1 2 3 4 5 6 7 8 9 10 |
|
См:
Отложенный навигационный UI¶
Когда пользователи перемещаются по приложению, данные для следующей страницы загружаются до ее отображения. Важно обеспечить обратную связь с пользователем в это время, чтобы приложение не казалось неотзывчивым.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
См:
Скелетный пользовательский интерфейс с <Suspense>
¶
Вместо того чтобы ждать данных для следующей страницы, можно отложить
данные, чтобы пользовательский интерфейс переходил к следующему экрану с пользовательским интерфейсом-заполнителем сразу же, пока данные загружаются.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
|
См.
Мутации данных¶
HTML-формы, как и ссылки, являются навигационными событиями. React Router поддерживает работу с HTML-формами с помощью маршрутизации на стороне клиента.
При отправке формы предотвращается обычное навигационное событие браузера и создается Request
с телом, содержащим FormData
отправки. Этот запрос отправляется на <Route action>
, соответствующий <Form action>
формы.
В действие передается свойство name
элементов формы:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Обычный запрос HTML-документа предотвращается и направляется в действие соответствующего маршрута (<Route path>
, совпадающего с <form action>
), включая request.formData
.
1 2 3 4 5 6 7 8 9 10 11 |
|
Ревалидация данных¶
Согласно десятилетним веб-соглашениям, когда форма отправляется на сервер, данные изменяются, и на экране появляется новая страница. Эта конвенция соблюдается в API мутации данных на основе HTML в React Router.
После вызова действий маршрута загрузчики всех данных на странице вызываются снова, чтобы пользовательский интерфейс автоматически обновлял данные. Никаких истекающих ключей кэша, никаких перезагрузок провайдеров контекста.
См:
Индикаторы занятости¶
Когда формы отправляются на маршрутные действия, вы имеете доступ к состоянию навигации для отображения индикаторов занятости, отключения наборов полей и т. д.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
См:
Оптимистичный пользовательский интерфейс¶
Знание того, что formData
отправляется в action, часто бывает достаточно, чтобы пропустить индикаторы занятости и сразу перевести пользовательский интерфейс в следующее состояние, даже если ваша асинхронная работа еще не завершена. Это называется "оптимистичный пользовательский интерфейс".
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
(Да, кнопки HTML могут иметь имя
и значение
).
Хотя чаще всего оптимизация пользовательского интерфейса осуществляется с помощью fetcher
, то же самое можно сделать и с обычной формой, используя navigation.formData
.
Фетчеры данных¶
HTML-формы являются образцом для мутаций, но у них есть одно существенное ограничение: одновременно можно использовать только одну форму, поскольку отправка формы - это навигация.
В большинстве веб-приложений необходимо, чтобы одновременно происходило несколько мутаций, например, список записей, каждая из которых может быть независимо удалена, отмечена как завершенная, понравилась и т. д.
Fetchers позволяет взаимодействовать с маршрутом actions и loaders, не вызывая навигации в браузере, но при этом получая все традиционные преимущества, такие как обработка ошибок, ревалидация, обработка прерываний и условий гонки.
Представьте себе список задач:
1 2 3 4 5 6 7 8 9 |
|
Каждая задача может быть помечена как завершенная независимо от остальных, со своим собственным состоянием ожидания и не вызывая навигации с fetcher:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
См:
Обработка гоночных условий¶
React Router отменяет устаревшие операции и автоматически фиксирует только свежие данные.
В любом асинхронном пользовательском интерфейсе существует риск возникновения условий гонки: когда асинхронная операция начинается после, а завершается до выполнения более ранней операции. В результате пользовательский интерфейс отображает неверное состояние.
Рассмотрим поле поиска, которое обновляет список по мере ввода пользователем текста:
1 2 3 4 |
|
Несмотря на то, что запрос для q?=ryan
вышел позже, он завершился раньше. При неправильной обработке результаты ненадолго станут правильными для ?q=ryan
, но затем перейдут к неправильным результатам для ?q=ry
. Дросселирования и дебаунсинга недостаточно (вы все равно можете прерывать проходящие запросы). Необходима отмена.
Если вы используете соглашения данных React Router, вы полностью и автоматически избегаете этой проблемы.
1 2 3 4 5 |
|
React Router справляется с условиями гонки не только при подобной навигации, но и во многих других случаях, например при загрузке результатов автозаполнения или при выполнении нескольких одновременных мутаций с помощью fetcher
(и его автоматических, одновременных повторных проверок).
Обработка ошибок¶
Подавляющее большинство ошибок вашего приложения обрабатывается React Router автоматически. Он перехватывает все ошибки, возникающие при:
- рендеринга
- загрузка данных
- обновлении данных
На практике это практически все ошибки в вашем приложении, за исключением тех, которые возникают в обработчиках событий (<button onClick>
) или useEffect
. В приложениях React Router их, как правило, очень мало.
При возникновении ошибки вместо отображения element
маршрута отображается errorElement
.
1 2 3 4 5 6 7 8 9 10 |
|
Если маршрут не имеет errorElement
, то ошибка переходит на ближайший родительский маршрут с errorElement
:
1 2 3 4 5 6 7 8 |
|
См:
Восстановление прокрутки¶
React Router эмулирует восстановление прокрутки браузера при навигации, ожидая загрузки данных перед прокруткой. Это гарантирует, что позиция прокрутки будет восстановлена в нужном месте.
Вы также можете настроить поведение, восстанавливая прокрутку не по местоположению (например, по пути к url) и запрещая прокрутку по определенным ссылкам (например, по вкладкам в середине страницы).
См:
API веб-стандартов¶
React Router построен на основе стандартных веб-интерфейсов. Loaders и actions получают стандартные объекты Web Fetch API Request
и могут также возвращать объекты Response
. Отмена выполняется с помощью Abort Signals, параметры поиска обрабатываются с помощью URLSearchParams
, а мутации данных - с помощью HTML Forms.
Когда вы лучше разбираетесь в React Router, вы лучше разбираетесь в веб-платформе.