Хорошо, вот моя проблема с React Router:

Мол, не поймите меня неправильно - это здорово. Вы можете помещать свои маршруты так же, как любые другие компоненты React, вы можете вкладывать их, дизайн элегантен, и в идеальном мире он «просто работает». Но… Документация оставляет желать лучшего. Кажется, что они делают простые задачи сложными. На этой неделе я работаю над проектом с использованием React Router. В последний раз я использовал его несколько недель назад, поэтому, естественно, мне нужно было немного освежить его. У меня только что возникли базовые вопросы, например:

Как предотвратить повторное монтирование всего приложения?
Я не хочу ничего особенного. Я просто хочу сказать: «Если пользователь идет сюда, визуализируйте это». Как мне сделать простые маршруты, которые имеют смысл?
Как предотвратить сопоставление React Router нескольких маршрутов и рендеринг слишком большого количества компонентов?
Как сделать так, чтобы моя панель NavBar работала правильно?
Как сделать так, чтобы кнопки работали правильно для навигации?

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

Если вы используете адресную строку в браузере, все ваше приложение будет повторно отображено. Следствием этого является то, что состояние вашего приложения будет стерто, включая все данные, которые вы загрузили. Сначала это меня немного сбило с толку, но в этом есть смысл. Если вы введете адрес и нажмете клавишу ВВОД, ваш браузер выполнит новый запрос GET, и, вероятно, этого уже не избежать. (Если я чего-то упускаю, я бы хотел, чтобы меня исправили!) Итак, как это обойти? Пока что я нашел два способа: во-первых, использовать компонент <Link>, предоставляемый React Router, вместо обычных тегов <a>. Я не совсем понимаю, чем они отличаются, но, похоже, это мешает перезагрузке приложения. Но что, если вы хотите иметь <button> такой вид, как «Создать пользователя», который перенаправляет вас на другую страницу? Я не знаю, насколько это «правильно», но то, что я делал,

  1. Имейте обработчик событий onClick для кнопки, которая устанавливает флаг redirect в значение true.
  2. В render методе компонента проверьте, истинно ли redirect. Если это так, визуализируйте <Redirect /> which - это компонент, предоставляемый React Router, который отправит вас по любому указанному вами маршруту.
  3. После этого вы должны не забыть установить флаг redirect обратно на false, иначе вы попадете в бесконечный цикл. Я думаю, что componentDidUpdate метод жизненного цикла React - хорошее место для этого.

Обновление: ничего из вышеперечисленного не требуется. Я обнаружил, что this.props.history.push - отличный способ заставить ваши кнопки работать правильно! Вам просто нужно использовать его вместе с withRouter, как описано ниже.

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

Например, предположим, что у вас есть группа таких маршрутов:

<Route path=‘/users’ component={UserList} />
<Route path=‘/accounts’ component={accounts} />
<Route exact path=‘/users/delete’ component={DeleteUserForm} />

Если пользователь переходит к /users/delete, какие компоненты будут отображаться? Вы можете подумать, что это всего лишь DeleteUserForm, но вы удивитесь. Оба /users и /users/delete содержат строку «/ users», поэтому она будет соответствовать обоим маршрутам и будут отображаться оба компонента. Это верно, даже если DeleteUserForm указывает «точное» свойство. Точный не препятствует отображению других маршрутов - он просто препятствует отображению этого определенного маршрута, если он не является точным совпадением. Таким образом, если пользователь перейдет к /users, будет отображаться только UserList, потому что «/ users» не является точным совпадением с /users/delete. Но если вы перейдете к /users/delete, оба маршрута совпадают.

(Между прочим, чтобы заставить React Router вести себя немного ближе к стандартным ожиданиям, вы можете заключить группу маршрутов внутри <Switch>. React Router отобразит только первый соответствующий маршрут и проигнорирует любой последующие маршруты в Switch.)

Чтобы добавить еще большей сложности, вот о чем еще нужно подумать: я говорил, что некоторые вещи «не отображаются», но на самом деле это не так. React Router фактически каждый раз отображает каждый маршрут. Он просто возвращает значение null, если совпадение не совпадает.

Хорошо, еще одна вещь: React Router предоставляет своим маршрутам несколько удобных реквизитов, которые дают вам некоторую полезную информацию:

совпадение: как мы сюда попали. this.props.match.path содержит URL-адрес, по которому был осуществлен переход. match.params содержит любые параметры URL (содержимое в URL после ?.)

местоположение: где мы сейчас находимся. this.props.location.pathname содержит ваше текущее местоположение.

история: полный объект истории.

При этом следует помнить, что только маршруты получают эти реквизиты. У других ваших компонентов их не будет. Но что, если мы хотим, чтобы эта информация была доступна, скажем, NavBar, чтобы мы могли отслеживать, где мы находимся? Для этого в React Router есть метод withRouter. Легко использовать. Допустим, у вас есть компонент NavBar React, объявленный как класс ES6:

class NavBar extends React.Component { … }
export default NavBar

Все, что вам нужно сделать, это обернуть его в WithRouter, вот так:

export default withRouter(NavBar);

О, и не забудьте import { withRouter } from ‘react-router-dom’

Теперь ваш компонент NavBar будет иметь эти реквизиты.

Надеюсь, этот пост будет полезен некоторым новичкам в React Router, таким как я. Если у вас есть какие-нибудь советы, я хотел бы их услышать!