«Статья была впервые опубликована в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>Компонент ожидает строку типаpathprop, чтобы указать путь, которому должен соответствовать маршрут. Например,<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>
)
**Примечание. **На главной странице есть маршрут сexactprop, который указывает, что домашняя страница будет сопоставляться только в том случае, если путь маршрута точно соответствует имени пути.
вложенность маршрутов
Маршрутизация страниц профиля игрока/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>использованиеtoprop для определения цели навигации, которая может быть строкой или объектом местоположения (содержащим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] При использованииchildrenprop, он будет отображаться, даже если путь не совпадает.
[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>компоненты могут приниматьlocationprop, что позволяет сопоставлять их с другим местоположением, а не только с их фактическим местоположением (текущий URL-адрес).
[7] props также можно передаватьstaticContextЭто свойство работает только при использовании рендеринга на стороне сервера.