React процветает, будучи одним из лучших инструментов для создания одностраничных приложений, что было довольно чуждой концепцией, когда я начал создавать свое первое приложение React. В то время я привык к концепции обслуживания отдельных веб-страниц всякий раз, когда пользователь перенаправляется с URL-адреса на другой, и поначалу было довольно сложно понять, как React обрабатывает навигацию.
Имея это в виду, этот пост в блоге призван изложить и объяснить основные аспекты навигации с использованием React Router, одного из самых, если не самого, популярного решения для навигации в приложении React.
В первом разделе ниже, пожалуйста, ссылайтесь на этот пример CodePen.
- Связь, коммутатор и маршрутизатор
Как упоминалось в предисловии к этому письму, маршрутизация в 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.