Як оновити до React Router 4

Незабаром після того, як я почав працювати на своїй нинішній посаді, команда зрозуміла, що нам доведеться перейти на React 16, щоб ми могли використовувати нову бібліотеку інтерфейсу, яку ми дуже хотіли прийняти.

Щоб зрозуміти, скільки часу потребуватиме це оновлення, ми переглянули всі наші поточні пакети, щоб перевірити, чи сумісні вони з React 16, і чи використовуємо ми все ще непідтримувані або застарілі пакети.

Початок нашої кодової бази був побудований розробниками, які використовували будь-яку бібліотеку з відкритим кодом або сторонніми розробниками, фактично не перевіряючи їх. Таким чином, ми виявили, що багато пакетів застаріли та потребували якнайшвидшої заміни.

Одним з найбільших сюрпризів для нас стало припинення react-router-redux. Ми використовували react-router-reduxспільно з React-Router v3. Це змусило нас критично замислитися над тим, чому ми спочатку використовували reduxнаш маршрутизатор.

Після того, як ми почали вивчати реакційний маршрутизатор v4, ми зрозуміли, що нові функції в значній мірі усунуть будь-яку причину використання додаткової бібліотеки для підключення нашого маршрутизатора і redux. Отже, це залишило нас у змозі просто перейти з реакційного маршрутизатора 3 на 4 і видалити   react-router-reduxз нашої програми.

Отже, мені було доручено оновити наш маршрутизатор до v4 після того, як я перебував у цьому положенні і працював з React близько 2 місяців. Це було тому, що оновлення з React Router 3 до React Router 4 здавалося, що це має бути тривіальним завданням. Але, як я швидко дізнався, це було дещо більше, ніж я передбачав.

Переглядаючи документацію, репозиторій GitHub та багато-багато відповідей на Stack Overflow, я нарешті склав кроки для оновлення та хотів поділитися своїми висновками - особливо, щоб пояснити, як і чому вносяться певні зміни.

Найбільша зміна, яку слід зазначити від творців React Router, полягає в тому, що оновлення React Router 3 до React Router 4 - це більше, ніж просто оновлення декількох бібліотек і функцій - це дозволяє вам принципово змінити роботу вашого маршрутизатора. Творці React Router хотіли повернутися до простого маршрутизатора, дозволяючи розробникові налаштувати його, як їм заманеться.

Я розділив цей посібник на 5 різних частин:

  1. Пакет
  2. Історія
  3. Маршрут
  4. Реквізит
  5. Інтеграція Redux

Пакет

Структура пакета React Router v4 змінена настільки, що більше не потрібно встановлювати React-Router - вам потрібно встановити react-router-dom(і видалити react-router), але ви нічого не втратите, оскільки він реекспортує весь react-routerекспорт. Це означає, що вам також доведеться оновити будь-які   react-routerоператори імпорту до react-router-dom.

Історія

Історія є важливою частиною маршруту, що дозволяє нам пам’ятати, звідки ми прийшли і де ми перебуваємо в даний час. Історія існує у різних формах для реакційних маршрутизаторів, і пояснення може зайняти деякий час. Отже, щоб зберегти цю статтю за темою, я просто порекомендую вам прочитати цю статтю, яка пояснює історію щодо реакції маршрутизатора 4. Ця стаття повинна охоплювати більшість випадків використання історії.

Маршрут

React Router v3 дозволив нам розмістити всі наші маршрути додатків в одному файлі, який ми будемо називати router.js. Однак React Router v4 дозволяє розміщувати маршрути в компонентах, які вони відображають. Ідея тут полягає в динамічній маршрутизації програми - іншими словами, маршрутизація відбувається під час візуалізації програми.

Однак якщо у вас є пристойний розмір застарілої кодової бази, з якою ви працюєте, ви, мабуть, не внесете такої великої зміни. На щастя, React Router v4 все ще дозволяє розміщувати всі маршрути в центральному файлі, ось як я буду створювати всі наші приклади. Однак є кілька старих компонентів та функцій, які потребують заміни.

IndexRoute

Раніше   IndexRouteвін використовувався як маршрут для деякого інтерфейсу за замовчуванням батьківського маршруту. Але, v4, IndexRouteбільше не використовується, оскільки ця функціональність тепер доступна в Route.

Для надання інтерфейсу за замовчуванням кілька маршрутів, що мають однаковий шлях, дозволять відображати всі пов'язані компоненти:

import { BrowserRouter as Router, Route } from 'react-router-dom';  // example of our route components    

Таким чином, всі компоненти - Home, Aboutі Contact- буде надавати. Через це ви більше не можете вкладати маршрути.

Крім того, щоб забезпечити кращу відповідність без використання IndexRoute, ви можете використовувати саме ключове слово.

import { BrowserRouter as Router, Route } from 'react-router-dom';  // example of our route components   

Ексклюзивна маршрутизація

Після додавання точного ключового слова “something.com/about”буде перенаправлено до того, як маршрутизатор побачить шлях “/about”. Але що, якщо у вас є інший шлях “/about/team”,? Як я вже зазначав, маршрутизатор відображатиме все, що відповідає. Отже, компоненти, пов’язані з обома “/about”і,   “/about/team”будуть відображатися. Якщо це те, що ви задумали, то це здорово! Однак, якщо це не те, що ви хочете, можливо, вам доведеться встановити комутатор навколо цієї групи маршрутів. Це дозволить відобразити перший шлях, який відповідає URL-адресі.

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';       

Зауважте, що ключове слово точне все ще має з’являтися для компонента Home - інакше воно відповідало б наступним маршрутам. Також зауважте, що ми маємо робити список “/about/team”раніше, “/about”тому маршрут переходить до Teamкомпонента замість Aboutкомпонента, коли він бачить   “something.com/about/team”. Якби він побачив “/about”перший, він зупинився б там і відтворив Aboutкомпонент, оскільки Switch відображає лише перший компонент, який відповідає.

Маршрут за замовчуванням

Маршрут за замовчуванням, або маршрут “спіймати усіх”, який зазвичай використовується для 404 сторінок, - це маршрут, яким ви користуєтесь, коли жоден з маршрутів не збігається.

У React Router v3 за замовчуванням Routeбуло:

У React Router v4 за замовчуванням Routeбуло змінено на:

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';       // this is our default route  

When  you don’t include a path in a Route, the component will always render.  So, as we discussed above, we can use Switch to get only one component  to render, and then place the “catch all” route very last (so it doesn’t  use that one before the Router gets a chance to check the rest of the  paths), so something will always render even if the other paths don’t  match.

onEnter

Previously,  you could use onEnter to make sure the component of the Route has all  of the information it needs or as a check (such as to make sure the user  is authenticated) before the component rendered.

This  feature has been deprecated because the new structure of Routes is that  they should act like components, so you should take advantage of component lifecycle methods instead.

In React Router v3:

Becomes:

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';        
... componentDidMount() { this.props.fetchInfo(); } ...

Props

In  React Router v4, the props passed through the router have changed, as  did the way they are accessed. The Route now passes three props:

  • history
  • location
  • match

history

history contains a lot of other properties and methods, so I won’t list all of  them, but here is a selection that might be most commonly used:

  • length: number of entries in the history stack
  • location: contains the same information as below
  • push(path, [state]): pushes new entry on history stack
  • goBack(): allows you to move the pointer on the history stack back 1 entry

It’s  important to note that history is mutable, and while it contains a location property, this instance of location shouldn’t be used since it  could have been changed. Instead, you want to use the actual location prop discussed below.

location

The location has properties:

  • pathname
  • search
  • hash
  • state

location.search is used to replace location.query and it must be parsed. I used  URLSearchParams to parse it. So a URL such as  “//something.com/about?string=’hello’” would be parsed as such:

... const query = new URLSearchParams(this.props.location.search) const string = query.get('string') // string = 'hello' ...

Additionally,  the state property can be used to pass the location-specific state of components through props. So, if you wanted to pass some information  from one component to another, you could use it like this:

... // To link to another component, we could do this:  // However, if we wanted to add state to the location, we could do this: const location = { pathname: '/path/', state: { fromDashboard: true }, }  ...

So, once we get to the component rendered by that path, we’ll have access to fromDashboard from location.state.fromDashboard.

match

match has the following properties:

  • params:  gets the dynamic segments of the path from the URL — for example if the  path is “/about/:id”, in the component, accessing  this.props.match.params will give you the id in the URL
  • isExact: true if the entire URL was matched
  • path: the path in the routes that was matched
  • url: the matched portion of the URL

Redux Integration

As  I addressed earlier, we found that in our case, we didn’t need to have an additional library to connect redux with our router, especially since our main use case for this — Blocked Updates — was covered by react  router.

Blocked Updates

In  some cases, the app doesn’t update when the location changes. This is called a “Blocked Update”. This can happen if both of these conditions  are met:

  1. The component is connected to Redux via connect()(Component).
  2. The component isn’t rendered by a

In these cases, I wrapped the component’s connect with withRouter.

This  allowed the router information to follow the component when it gets linked to, so the app still updates when the Redux state changes.

And that’s it!

This upgrade took me over a week — a few days of trying to figure out how to do it at all, and then another few days to start actually making changes. Upgrading to React Router 4 is a huge change not to be taken lightly, but it’ll make your router a lot more lightweight and easy to use.

Please don’t hesitate to comment/ask questions!