Со времен зарождения современного фронтенда были попытки сделать продвинутый фронт с многостраничным интерфейсом. Технически это не представляет особой сложности, однако нет особого смысла в многостраничном интерфейсе без ссылок на эти страницы. С этим же были проблемы - при любой попытке смены адресной строки браузер упорно переходил на другую страницу, т.е. обращался к серверу и сбрасывал JS, подгружая новые скрипты. Это если страница реально существовала на сервере. Обычно же 404.
#
-ссылкиПри переходе по ссылкам внутри страницы (используя ) браузер, очевидно, страницу не перезагружает.
Этим длительное время пользовались первые SPA типа gmail. На таких сервисах
роутинг, аналогичный роутингу в express реализуется после символа #
в адресе,
таким образом с точки зрения браузера все эти "переходы" по ссылкам происходят внутри одной
страницы, чем и пользуется JS, прослушивая события изменения адреса и перерисовывая содержимое
страницы.
HTML5 позволяет отлавливать любое изменение адреса, а так же управлять историей браузера. Таким образом можно полностью просимулировать работу страниц внутри SPA, как будто бы они загружаются с сервера.
Потому что физически это одна страница, которая просто показывает пользователю фейковые адреса и разный DOM.
По образу и подобию роутинга в express, только адрес, который сопоставляется с шаблоном приходит не из браузера на бэк, а обрабатывается в самом браузере.
С точки зрения React каждая страница - это компонент. Роутинг прописывается в декларативной форме в JSX.
$ npm install --save react-router-dom
import {Router, Route, Link} from 'react-router-dom';
import createHistory from "history/createBrowserHistory";
<Router history = {createHistory()}>
<div>
<Route path="/chat/:param1/:param2" component = {ChatPage} />
<Route path="/" component = { MainPage } exact />
</div>
</Router>
Router
обрамляет все маршруты и обеспечивает интеграцию с Browser History APIRoute
принимает props
:
path
- шаблон адреса, как в express (обратите внимание на param1
и param2
)component
- класс компонента.exact
- нужен что бы маршрут срабатывал только при полном совпадении.
Принимают параметры шаблона адреса в props
class ChatPage extends Component {
render() {
console.log(this.props)
return (
<div className="App">
{this.props.match.params.param1} <br/>
{this.props.match.params.param2}
</div>
)
}
}
Link
Компонент Link
предназначен для создания ссылок.
<Link to='/'>...go to main</Link>
Switch
Компонент Switch
выбирает первый подходящий маршрут, остальные
игнорирует:
<Router history = {createHistory()}>
<div>
<Switch>
<Route path="/chat/" component = { ChatPage } />
<Route path="/" component = { MainPage } exact />
<Route component = { NotFound } />
</Switch>
</div>
</Router>
Redirect
Иногда нужно назначить перенаправление с одного адреса на другой.
В таком случае поможет компонент Redirect
:
<Router history = {createHistory()}>
<div>
<Switch>
<Route path="/chat/" component = {ChatPage} />
<Route path="/" component = { MainPage } exact />
<Redirect from="/main" to="/" />
<Route component = { NotFound } />
</Switch>
</div>
</Router>
При посещении адреса /main
будет автоматически происходить переход на /
и работать компонент MainPage
Зачастую после сохранения тех или иных форм нужно перейти на другую страницу, т. е. сменить адрес в адресной строке таким образом, что бы React Router это обработал согласно конфигурации маршрутов.
Это можно сделать с помощью рендеринга компонента Redirect
без
from
.
В относительно крупных проектах возникает надобность разделить разные части сайта на разные наборы маршрутов.
Например:
/
Главная страница/dashboard
Личный кабинет/admin
Админка
/admin/
/admin/dashboard
Админский кабинетВ такой структуре логично отделить маршруты общей и административной части сайта.
//App
<Router history = {createHistory()}>
<div>
<Switch>
<Route path="/" component = { MainPage } exact />
<Route path="/dashboard" component = { DashboardPage } />
<Route path="/admin" component = { AdminPage } />
<Route component = { NotFound } />
</Switch>
</div>
</Router>
...
class AdminPage extends Component {
render(){
let root = this.props.match.url
return(
<div>
<Route path={`${root}/`}
component={ AdminMainPage }
/>
<Route path={`${root}/dashboard`}
component={ AdminDashboardPage }
/>
</div>
)
}
}