«Статья была впервые опубликована вGitHub Blog』
Оригинальный адрес:A Simple React Router v4 Tutorial
React Router v4 — это популярный пакет React, полностью переписанный на React, а предыдущие версии React Router были настроены на использование неизвестных псевдокомпонентов. Теперь с React Router v4 все «просто компоненты».
В этом уроке мы создадим локальную страницу «спортивные команды» и рассмотрим все основные потребности для создания нашего сайта и маршрутизации, в том числе:
- выберите
router
. - Создайте
routes
. - Навигация по ссылкам между маршрутами.
код
Установить
React Router теперь разделен на три пакета:react-router
,react-router-dom
,react-router-native
.
вы не должны устанавливать напрямуюreact-router
, этот пакет предоставляет основные компоненты и функции маршрутизации для приложений React Router, а два других пакета предоставляют компоненты, специфичные для среды (браузер иreact-native
соответствующей платформе), но они также будутreact-router
Экспортированные модули экспортируются снова.
Вы должны выбрать пакет из двух, который подходит для вашей среды разработки, нам нужно создать веб-сайт (работает в браузере), поэтому нам нужно установитьreact-router-dom
npm install --save react-router-dom
Router
Начиная новый проект, вы должны решить, какой из них использоватьrouter
. Для проектов, работающих в браузере, мы можем выбрать<BrowserRouter
и<HashRouter>
компоненты,<BrowserRouter>
Следует использовать в проектах, где сервер обрабатывает динамические запросы (умеет обрабатывать произвольные URI),<HashRouter>
Используется для обработки статических страниц (отвечает только на запросы известных файлов).
Обычно рекомендуется использовать<BrowserRouter>
, но если сервер обрабатывает только запросы статических страниц, используйте<HashRouter>
Тоже достаточное решение.
Для нашего проекта мы предполагаем, что все страницы динамически генерируются сервером, поэтому нашrouter
Выбор компонентов<BrowserRouter>
.
History
каждыйrouter
создастhistory
Объект, используемый для отслеживания текущей позиции [1] и для повторного рендеринга страницы при ее изменении. Другие компоненты, предоставляемые React Router, зависят отcontext
хранится наhistory
объекты, поэтому они должны быть вrouter
Внутренний рендеринг объектов.никто неrouter
Объекты React Router для элементов-предков не будут работать, если вы хотите узнать больше оhistory
знание объекта, может относиться кэта статья.
оказывать<Router>
Компонент маршрутизатора может принимать только один дочерний элемент.Чтобы соответствовать этому ограничению, создайте<App>
компонентов для рендеринга других приложений будет очень удобно (отделение приложения от роутера также имеет смысл для рендеринга на стороне сервера, так как мы переключаемся на серверную сторону<MemoryRouter>
можно быстро использовать повторно<App>
)
import { BrowserRouter } from 'react-router-dom'
ReactDOM.render((
<BrowserRouter>
<App />
</BrowserRouter>
), document.getElementById('root'))
Теперь, когда мы выбрали маршрутизатор, мы можем начать рендеринг нашего реального приложения.
<App>
Наше приложение определено в<App>
компонентов, чтобы упростить<App>
, делим наше приложение на две части,<Header>
Компоненты содержат навигацию, которая ссылается на другие страницы,<Main>
Компоненты содержат остальные части, которые необходимо визуализировать.
// this component will be rendered by our <___Router>
const App = () => (
<div>
<Header />
<Main />
</div>
)
Note:Вы можете расположить свое приложение так, как хотите, а разделение маршрутов и навигации упрощает понимание того, как работает React Router.
Начнем с рендеринга содержимого маршрутизации.<Main>
Компоненты запускаются.
Routes
<Route>
Компоненты являются основной частью React Router. Если вы хотите отобразить что-то где угодно, когда путь совпадает, вам следует создать<Route>
элемент.
Path
Один<Route>
Компонент ожидает строку типаpath
prop, чтобы указать путь, которому должен соответствовать маршрут. Например,<Route path='/roster/'
будет соответствовать/roster
[2] Начальный путь, когда текущий путь иpath
При совпадении маршрут будет отображать соответствующий элемент React. Когда путь не совпадает, маршрут не будет отображать никаких элементов [3].
<Route path='/roster'/>
// when the pathname is '/', the path does not match
// when the pathname is '/roster' or '/roster/2', the path matches
// If you only want to match '/roster', then you need to use
// the "exact" prop. The following will match '/roster', but not
// '/roster/2'.
<Route exact path='/roster'/>
// You might find yourself adding the exact prop to most routes.
// In the future (i.e. v5), the exac t prop will likely be true by
// default. For more information on that, you can check out this
// GitHub issue:
// https://github.com/ReactTraining/react-router/issues/4958
**Примечание. **При сопоставлении маршрутов React Router заботится только об относительной части пути, поэтому следующий URL-адрес
http://www.example.com/my-projects/one?extra=false
React Router только попытается сопоставить/my-projects/one
.
путь совпадения
React Router используетpath-to-regexp
пакет для определения путиpath
если реквизит соответствует текущему пути, он будетpath
Строка преобразуется в регулярное выражение для соответствия текущему пути, примерноpath
Дополнительные необязательные форматы строк см.path-to-regexp
Документация.
Когда маршрут совпадает с путем,match
Объект будет передан в качестве реквизита
-
url
- часть текущего пути, которая соответствует маршруту -
path
- маршрутизированныйpath
-
isExact
-path === pathname
-
params
- один содержитpathname
одеялоpath-to-regexp
захваченный объект
**Примечание: **В настоящее время путь маршрута должен быть абсолютным путем [4].
Создадим собственный маршрут
<Route>
s можно создавать в любом месте роутера, но вообще логичнее их рендерить там же, можно использовать<Switch>
компоненты для объединения<Route>
Да,<Switch>
пройдет через егоchildren
элемент (маршрут), то только первый соответствующийpathname
.
Для нашего веб-сайта пути, которые мы хотим сопоставить, следующие:
-
/
- Домашняя страница -
/roster
- Список команд -
/roster/:number
- Информация об игроке с использованием номера футболки игрока, чтобы отличить -
/schedule
- Расписание команды
Чтобы соответствовать пути, нам нужно создать бэндpath
опора<Route>
элемент
<Switch>
<Route exact path='/' component={Home}/>
{/* both /roster and /roster/:number begin with /roster */}
<Route path='/roster' component={Roster}/>
<Route path='/schedule' component={Schedule}/>
</Switch>
<Route>
что будет визуализировано
Маршруты могут принимать три реквизита, чтобы определить элемент для отображения при совпадении маршрута.<Route>
Элементы предоставляют способ определить, что отображать.
-
<component>
- компонент React, когда он сcomponent
Когда маршрут реквизита совпадает, маршрут вернет компонент типа component, предоставленный реквизитом (черезReact.createElement
рендеринг). -
render
— метод, возвращающий элемент React [5], сcomponent
Точно так же он вызывается при совпадении пути. Это очень удобно при написании встроенной формы для рендеринга и передачи параметров. -
children
- Метод, возвращающий элемент React. В отличие от первых двух, этот методвсегдабудет отображаться независимо от того, соответствует ли маршрут текущему пути.
<Route path='/page' component={Page} />
const extraProps = { color: 'red' }
<Route path='/page' render={(props) => (
<Page {...props} data={extraProps}/>
)}/>
<Route path='/page' children={(props) => (
props.match
? <Page {...props}/>
: <EmptyPage {...props}/>
)}/>
В общем, мы обычно используемcomponent
илиrender
,children
Существует не так много вариантов использования, и, как правило, лучше ничего не отображать, когда маршруты не совпадают. В нашем случае нам не нужно передавать какие-либо параметры маршруту, поэтому мы используем<component>
.
Зависит от<Route>
Визуализированный элемент будет иметь набор реквизитов, в том числеmatch
объект, текущийlocation
Объект [6] иhistory
Объект (созданный маршрутизатором) [7].
<Main>
Теперь, когда мы определили структуру маршрутов, нам осталось их реализовать. В нашем приложении мы будем<Main>
Рендеринг в компоненте<Switch>
и<Route>
, они будут в<main>
Визуализация HTML-элементов в формате .
import { Switch, Route } from 'react-router-dom'
const Main = () => (
<main>
<Switch>
<Route exact path='/' component={Home}/>
<Route path='/roster' component={Roster}/>
<Route path='/schedule' component={Schedule}/>
</Switch>
</main>
)
**Примечание. **На главной странице есть маршрут сexact
prop, который указывает, что домашняя страница будет сопоставляться только в том случае, если путь маршрута точно соответствует имени пути.
вложенность маршрутов
Маршрутизация страниц профиля игрока/roster/:number
в<Roster>
компоненты, не входящие в<Switch>
середина. Однако, пока имя пути указано/roster
начни, будет<Roster>
Рендеринг компонентов.
существует<Roster>
В компоненте мы будем отображать два пути:
-
/roster
- только если путь точно совпадает/roster
будет отображаться, когда мы захотим указать путьexact
параметр. -
/roster/:number
- этот маршрут использует параметр пути для захвата/roster
Часть имени пути, за которой следует.
const Roster = () => (
<Switch>
<Route exact path='/roster' component={FullRoster}/>
<Route path='/roster/:number' component={Player}/>
</Switch>
)
Маршруты с одинаковым префиксом удобно ставить в один и тот же компонент, это упрощает родительский компонент и позволяет нам рендерить все компоненты с одинаковым префиксом в одном месте.
Например,<Roster>
доступно для всех/roster
Маршрут в начале отображает заголовок
const Roster = () => (
<div>
<h2>This is a roster page!</h2>
<Switch>
<Route exact path='/roster' component={FullRoster}/>
<Route path='/roster/:number' component={Player}/>
</Switch>
</div>
)
Параметр пути
Иногда нам нужно захватить несколько параметров в имени пути, например, в маршрутизации нашего профиля игрока мы можем перейти к путиpath
Добавлен параметр пути для захвата номера игрока.
:number
Частичное представление находится в пути/roster/
Следующий контент будет храниться вmatch.params.number
. Например,/roster/6
Имя пути сгенерирует объект params следующим образом.
{ number: '6' } // note that the captured value is a string
<Player>
Использование компонентовprops.match.params
объект, чтобы решить, какие данные игрока должны быть отображены.
// an API that returns a player object
import PlayerAPI from './PlayerAPI'
const Player = (props) => {
const player = PlayerAPI.get(
parseInt(props.match.params.number, 10)
)
if (!player) {
return <div>Sorry, but the player was not found</div>
}
return (
<div>
<h1>{player.name} (#{player.number})</h1>
<h2>{player.position}</h2>
</div>
)
оpath
С параметрами можно ознакомитьсяpath-to-regexp
Документация.
прямо рядом с<Player>
, есть еще один<FullRoster>
,<Schedule>
и<Home>
компоненты.
const FullRoster = () => (
<div>
<ul>
{
PlayerAPI.all().map(p => (
<li key={p.number}>
<Link to={`/roster/${p.number}`}>{p.name}</Link>
</li>
))
}
</ul>
</div>
)
const Schedule = () => (
<div>
<ul>
<li>6/5 @ Evergreens</li>
<li>6/8 vs Kickers</li>
<li>6/14 @ United</li>
</ul>
</div>
)
const Home = () => (
<div>
<h1>Welcome to the Tornadoes Website!</h1>
</div>
)
Links
Наконец, нашему веб-сайту необходимо перемещаться между страницами, если мы используем<a>
Навигация с вкладками загрузит совершенно новую страницу. React Router предоставляет<Link>
компонент, чтобы избежать этого при нажатии<Link>
, URL-адрес будет обновлен, и страница будет отображать содержимое без загрузки всей новой страницы.
import { Link } from 'react-router-dom'
const Header = () => (
<header>
<nav>
<ul>
<li><Link to='/'>Home</Link></li>
<li><Link to='/roster'>Roster</Link></li>
<li><Link to='/schedule'>Schedule</Link></li>
</ul>
</nav>
</header>
)
<Link>
использованиеto
prop для определения цели навигации, которая может быть строкой или объектом местоположения (содержащимpathname
, search
, hash
иstate
Атрибуты). Когда просто строка, она будет преобразована в объект местоположения
<Link to={{ pathname: '/roster/7' }}>Player #7</Link>
**Примечание: **В настоящее время путь ссылки должен быть абсолютным путем.
пример
Два онлайн-примера:
Примечания!
[1] location — это объект, содержащий параметры, описывающие различные части URL-адреса.
// a basic location object
{ pathname: '/', search: '', hash: '', key: 'abc123' state: {} }
[2] может быть бездорожьем<Route>
, этот маршрут будет соответствовать всем путям, поэтому к нему можно будет легко получить доступ, хранящийся вcontext
объекты и методы на .
[3] При использованииchildren
prop, он будет отображаться, даже если путь не совпадает.
[4] пусть<Route>
песок<Link>
s Работа по принятию относительного пути не завершена, относительный<Link>
s более сложны, чем кажутся, потому что они требуют родительского компонентаmatch
объект для работы вместо текущего URL.
[5] Это базовый компонент без гражданства,component
иrender
Разница в том,component
Будет использоватьсяReact.createElement
создать элемент,render
Используется для обработки компонента как функции. Если вы хотите создать встроенную функцию и передать ее вcomponent
,Такrender
было бы лучше, чемcomponent
Приходит намного быстрее.
<Route path='/one' component={One}/>
// React.createElement(props.component)
<Route path='/two' render={() => <Two />}/>
// props.render()
[6] <Route>
и<Switch>
компоненты могут приниматьlocation
prop, что позволяет сопоставлять их с другим местоположением, а не только с их фактическим местоположением (текущий URL-адрес).
[7] props также можно передаватьstaticContext
Это свойство работает только при использовании рендеринга на стороне сервера.