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

Имея это в виду, этот пост в блоге призван изложить и объяснить основные аспекты навигации с использованием React Router, одного из самых, если не самого, популярного решения для навигации в приложении React.

В первом разделе ниже, пожалуйста, ссылайтесь на этот пример CodePen.

  1. Связь, коммутатор и маршрутизатор

Как упоминалось в предисловии к этому письму, маршрутизация в React не включает в себя замену ресурсов HTML, CSS или JavaScript, которые в настоящее время обслуживаются, или перезагрузку содержимого браузера. Вместо этого использование таких библиотек, как react-router, позволяет динамически загружать и выгружать контейнеры в зависимости от текущего местоположения URL, и все это происходит на стороне клиента. Имея это в виду, React Router можно в более общем смысле понимать как оболочку, которая обрабатывает условный рендеринг на основе URL-пути.

Для этого разработчики используют основные строительные блоки <Route>, <Switch> и <Link>. Давайте рассмотрим базовый пример использования этих трех компонентов:

Во-первых, давайте создадим несколько простых текстовых компонентов. Эти компоненты являются заменой реальных компонентов, которые можно заменять и заменять в навигации. HelloBanner будет div, содержащим простое сообщение «Hello», а WorldBanner — «World!»:

const HelloBanner: React.FunctionComponent = () => {
  return (
    <div id="banner_hello" className="banner">
      <span>Hello Banner is currently displayed. We are currently in path "/hello"</span>
    </div>
  ) 
}

const WorldBanner: React.FunctionComponent = () => {
  return (
    <div id="banner_world" className="banner">
      <span>Hello Banner is currently displayed. We are currently in path "/world"</span>
    </div>
  ) 
}

Теперь давайте представим макет обычного веб-приложения с верхней панелью навигации. Панель навигации содержит ссылки на каждый раздел приложения, а в теле отображается содержимое текущей веб-страницы. Скелетный код для этого контейнера в React будет выглядеть примерно так:

class AppContainer extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div id="div_app_container" className="app-container">
        <div id="div_nav" className="nav-bar">
          <span>Navigation bar</span>
          <Link to="/hello">
            <span>Link to /hello</span>
          </Link>
          <Link to="/world">
            <span>Link to /world</span>
          </Link>
          <Link to="/clearlyinvalidpath">
            <span>Link to a clearly invalid path.</span>
          </Link>
        </div>
        <div id="main_container" className="main-container">
          <span>Main Container</span>
          <Switch>
            <Route exact path="/">
              <div>
                <span>
                  Default container. We are in root path
                </span>
              </div>
            </Route>
            <Route path="/hello" component={HelloBanner} />
            <Route path="/world">
              <WorldBanner />
            </Route>
            <Redirect to="/" />
          </Switch>
        </div>
      </div>
    );
  }
}

ReactDOM.render(
  <BrowserRouter>
    <AppContainer />
  </BrowserRouter>,
  document.getElementById("app")
);

Если вы сейчас смотрите на визуализацию этой структуры из CodePen, вы увидите очень простой пользовательский интерфейс:

Нажав на <Link> на панели навигации, вы «перейдете» к соответствующим путям. По сути, это двоякое действие:

  • Обновление текущего пути браузера до указанного пути.
  • Обновите все компоненты <Route> для повторного рендеринга в соответствии с текущим путем.

Это продемонстрировано на примере приложения. Как только вы нажмете на ссылку /hello или /world, соответствующий компонент будет заменен в контейнере <Switch>.

Несколько примечательных моментов из примера кода:

  • Компонент <Switch> позволяет переключаться между <Route> и отображать правильный компонент с заданным URL-адресом. Однако компоненты <Route> не обязательно помещать внутрь файла <Switch>. В автономном режиме <Route> будет просто отображаться, когда путь URL-адреса соответствует его собственному реквизиту path.
  • Компонент <Redirect> в конце действует как маршрут по умолчанию. Если ни один из других маршрутов не совпадает с текущим URL-адресом, он просто перенаправляет пользователя обратно в root.

2. Программное перенаправление

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

Для традиционной настройки к объекту history можно получить доступ через свойства компонента через пользователя компонента withRouter более высокого порядка:

import * as React from "react";
import { RouteComponentProps, withRouter } from "react-router-dom";

export interface SampleComponentProps extends RouteComponentProps {
  // props go here
}
export interface SampleComponentStateState {
  // states go here
}

class SampleComponent extends React.Component<SampleComponentProps, SampleComponentStateState> {
  constructor(props: any) {
    super(props);
  }

  performRedirect = () => {
    const { history } = this.props;

    history.push("/desired-pathname")
  }

  render() {
    return <div/>
  }
}

export default withRouter<SampleComponentProps>(SampleComponent);

В приведенном выше примере вы можете увидеть все компоненты, необходимые для извлечения объекта history, а также вызов history.push() для выполнения перенаправления.

Для более обновленного подхода React Router представил хук useHistory, который должен более естественно сочетаться при программировании с интенсивным рабочим процессом React Hooks.

3. Передача состояний при переадресации

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

При использовании перенаправления компонента <Link> заполните реквизит to объектом, который содержит новый путь, а также состояния, а не просто строку для имени пути:

<Link
  to={{
    pathname: "/desired-pathname",
    state: {
      stateName: "state to be passed."
    }
  }}
>
  Link text here.
</Link>

Тот же объект можно использовать в качестве аргумента вызова history.push() для достижения аналогичных результатов:

history.push({
  pathname: "/desired-pathname",
  state: {
    stateName: "state to be passed."
  }
})

Как только состояние было включено в перенаправление, на принимающей стороне вы можете извлечь состояние из объекта history.location.state:

В приведенном выше примере доступ к состоянию in componentDidMount.

import * as React from "react";
import { RouteComponentProps, withRouter } from "react-router-dom";

export interface ReceivingComponentProps extends RouteComponentProps {
  // props go here
}
export interface ReceivingComponentStateState {
  // states go here
}

class ReceivingComponent extends React.Component<ReceivingComponentProps, ReceivingComponentStateState> {
  constructor(props: any) {
    super(props);
  }

  componentDidMount() {
    const { history } = this.props;
    if (history.location.state && history.location.state.stateName) {
      // stateName can be accessed here if it is passed in from a previous redirect action.
      console.log(history.location.state.stateName);
    }
  }

  render() {
    return <div/>
  }
}

export default withRouter<ReceivingComponentProps>(ReceivingComponent);

4. Напутствие

К этому моменту, надеюсь, мы рассмотрели все основные моменты, которые помогут вам начать работу с навигацией с помощью React Router. Я надеюсь, что эта статья была информативной и помогла вам понять навигацию в React, а также помогла вам создать ваше следующее приложение React.

Первоначально опубликовано на https://www.loginradius.com.