Как да надстроите до React Router 4

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

За да разберем колко време ще изисква това надстройване, разгледахме всички наши текущи пакети, за да видим дали са съвместими с React 16 и дали все още използваме неподдържани или остарели пакети.

Началото на нашата кодова база е изградено от разработчици, които са използвали каквото искат с отворен код или библиотека на трети страни, без всъщност да ги проверяват. По този начин установихме, че много от пакетите са остарели и трябва да бъдат заменени ASAP.

Една от най-големите изненади за нас беше отхвърлянето на react-router-redux. Използвахме react-router-reduxзаедно с реактор-рутер 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 се промени така, че вече не е необходимо да инсталирате reakter-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 изобразява само първия компонент, който съвпада.

Маршрут по подразбиране

Маршрут по подразбиране или маршрут „catch all“, често използван за 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!