Обзор функций¶
Маршрутизация на стороне клиента¶
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, вы лучше разбираетесь в веб-платформе.