Вложенные маршруты — React Router

Ознакомьтесь с предыдущим постом о маршрутах:

https://dev.to/kibetamos/react-router-31oa

Мы работали с маршрутизаторами, которые достаточно малы, чтобы их можно было полностью отобразить в одном файле. Но по мере роста приложения может оказаться полезным разделить маршрутизатор и написать маршруты ближе к месту написания соответствующей логики пользовательского интерфейса.

Давайте вернемся к нашему примеру с сайтом технических статей и представим, что команда инженеров разрабатывает функцию Categories, которая будет упорядочивать статьи технических новостей по категориям — фронт-энд, бэк-энд, мобильная разработка и т. д. В дополнение к компоненту Categories (который будет отображать ссылки на каждую отдельную категорию), команда создала представление Category, которое будет отображать все статьи для данной категории.

Раньше мы могли написать маршрутизатор, подобный этому:

// In the top level App component
<Router>
  <Route path={'/categories/:categoryName'}>
    <Category />
  </Route>
  <Route path={'/categories'}>
    <Categories />
  </Route>
  {/* Other Routes */}
</Router>
Войти в полноэкранный режим Выход из полноэкранного режима

В таком способе маршрутизации нет ничего плохого, но как только вы начнете внедрять больше функций в свое приложение, вы можете обнаружить, что все маршруты, заключенные в одном маршрутизаторе, становятся немного громоздкими. Выход из этой ситуации — освоить рендеринг маршрутов из компонентов, вложенных в ваше приложение.

Например, рассмотрим компонент Categories, который итерирует список категорий и создает ссылки для каждой категории:

function Categories ({ categories }) {
  return (
    <ul>
      {
        categories.map(category =>
          <li>
            <Link to={`/categories/${category}`}>
              {category}
            </Link>
          </li>
        )
      }
    </ul>
  );
};
Вход в полноэкранный режим Выход из полноэкранного режима

Щелчок по ссылке, созданной этим компонентом, приведет к изменению URL, например, на /categories/html. Согласно нашему ранее определенному Router, маршрут ‘/categories/:categoryName’ будет соответствовать, и компонент Category будет отрисован.

Обратите внимание, что в коде компонента Categories не указано, какой компонент будет отображаться, когда пользователь нажмет на одну из ссылок категории (это компонент Category). Мы должны вернуться к файлу компонента App верхнего уровня, где определен Router, чтобы увидеть, что компонент Category будет отображаться при изменении URL на /categories/html. Такое разделение причины и следствия не является идеальным.

Поскольку React Router обрабатывает маршрутизацию динамически (например, маршруты существуют, когда они отображаются), вы можете отобразить маршрут в любом месте вашего приложения. В данном случае мы можем переместить маршрут, который отображает отдельный компонент Category, в компонент Categories, где определены ссылки на этот маршрут.

import { Link, Route } from 'react-router-dom'

function Categories ({ categories }) {
  return (
    <div>
      <ul>
        {
          categories.map(category => 
            <li>
              <Link to={`/categories/${category}`}>
                {category}
              </Link>
            </li>
          )
        }
      </ul>

      <Route path={'/categories/:categoryName'}>
        <Category />
      </Route>
    </div>
  )
}
Вход в полноэкранный режим Выйти из полноэкранного режима

В результате маршрутизатор верхнего уровня может быть упрощен:

// In the top level App component
<Router>

  {/* The Category route has been removed. */}

  <Route path={'/categories'}>
    <Categories />
  </Route>

  {/* Other Routes */}
</Router>
Войти в полноэкранный режим Выход из полноэкранного режима

Переписывание маршрутов таким образом делает очевидным, что произойдет, когда пользователь нажмет на ссылку. Это также позволяет нам очистить наш маршрутизатор верхнего уровня, удалив маршрут для отдельной категории. Разделение маршрутов таким образом также делает приложение более эффективным, поскольку маршруты отображаются не всегда. Вместо этого маршруты отображаются только тогда, когда этого требует логика пользовательского интерфейса.

useRouteMatch
Вложенность маршрутов улучшает организацию компонентов Link и Route в нашем приложении. Как и в компоненте Categories, обычно вложенные компоненты Link и Route исходят из одного и того же базового URL (в данном случае URL /categories).

Вместо того чтобы писать полный путь URL, было бы гораздо гибче, если бы мы могли создавать относительные пути на основе URL /categories. React Router предоставляет хук useRouteMatch(), который позволяет сделать это невероятно просто.

Ниже показано базовое использование в компоненте BandPage, который отображается по маршруту ‘/bands/:band/’. Предположим, что пользователь посещает страницу /bands/queen/. Эта страница должна отображать список относительных ссылок, основанных на различных песнях группы Queen. Маршрут также создается для отображения SongPage для любой выбранной песни:

import { useRouteMatch, Link, Route } from 'react-router-dom';
import { SongPage } from '../SongPage.js'

function BandPage ({ songs }) {
  let { path, url } = useRouteMatch();

  // path = '/band/:band'
  // url = '/band/queen' 

  // Render a list of relative Links and a Route to render a SongPage
  return (
    <div>
      <ul>
        {
          songs.map(songName =>
            <li>
              <Link to={`${url}/song/${songName}`}> 
                {category}
              </Link>
            </li>
          )
        }
       </ul>

       <Route path={`${path}/song/:songName`}>
         <SongPage />
       </Route>
     </div>
  )
}
Вход в полноэкранный режим Выход из полноэкранного режима

Давайте разберем это на части.

  1. UseRouteMatch() вызывается внутри компонента и возвращает объект со свойствами url и path. Этот объект иногда называют объектом соответствия:
  2. Свойство path содержит шаблон динамического пути с параметрами URL (например, /bands/:band) и должно использоваться для создания реквизитов относительного пути для компонентов Route (например, /bands/:band/songs/:songName).
  3. Свойство url имеет заполненные значения параметров URL (например, /bands/queen) и должно использоваться для создания реквизитов относительного пути для компонентов Link (например, /bands/queen/songs/we_are_the_champions).

Давайте посмотрим, как мы можем использовать эти значения в компоненте Categories для создания относительных маршрутов к компоненту Category:

import { Link, Route, useRouteMatch } from 'react-router-dom'

function Categories ({ categories }) {
  let { path, url } = useRouteMatch();

  // path = '/categories'
  // url = '/categories' 

  // Even though path and url are the same in this case, use path for relative Routes and url for relative Links
  return (
    <div>
      <ul>
        {
          categories.map(category =>
            <li>
              <Link to={`${url}/${category}`}>
                {category}
              </Link>
            </li>
          )
        }
       </ul>

       <Route path={`${path}/:category`}>
        <Category />
       </Route>
     </div>
  )
}
Войти в полноэкранный режим Выход из полноэкранного режима

Использование относительных значений url и path для создания компонентов Link и Route гарантирует, что они точно направят пользователя на правильный URL, независимо от маршрута, который вызвал рендеринг компонента Categories.

Оцените статью
Procodings.ru
Добавить комментарий