Как обновить react router dom

от admin

How to update React Router in 4 easy steps?

In this article, I’ll go over what’s new in React-Router version 6 and, of course, I’ll also show you how to update an existing React app that is using React-Router version 5 to React-Router version 6.

This is significant because React-Router is one of the most popular and significant React packages available. Many React projects need routing, so many React projects do use React-Router.

You can, of course, look at reactrouter.com’s official website and the documentation there.

In particular, there is an upgrading guide there that includes specific upgrading instructions as well as information on what’s new and changed.
This is a lengthy document, so if you want all the details, you should definitely also dive into it.

However, version 6 is far superior to version 5 despite the fact that it is quite easy to upgrade and that not much has changed in the actual code that we create. As a result, if you can, you should definitely think about doing so.

The greatest difference between React Router 3 and React Router 4 is that it allows you to radically alter how your Router functions rather than simply updating a few packages and functionalities. React developers intended to return to a straightforward Router that programmers could modify whatever they wished.

This guide is divided into 5 sections as follows:

1. Route:

We were able to consolidate all of our application routes into a single file, which we’ll call router.js, thanks to React Router v3. React Router v4 does, however, let you insert Routes within the components that they’re rendering. The goal is to dynamically route the application, which means that the routing happens while the application is being rendered.

You probably won’t be making a change that significant if the legacy code base you’re working with is sizable.

React Router v4 still permits you to consolidate all of the routes into a single file, which is how I’ll build all of our examples. However, there are a few outdated parts and elements that require replacement.

What is Index Route?

Some default UI of a parent Route utilized IndexRoute as its route. However, since Route now has this feature, IndexRoute is no longer necessary in version 4.

Multiple Routes with the same route will allow all connected components to render for default UI:

Or

What is Exclusive Routing?

When the router detects a path with the prefix “/about,” it will direct traffic to “something.com/SignIn” after adding the precise keyword. But what if you have the “/SignIn/team” path instead? The router will display anything that matches, as I have said. As a result, both the “/SignIn” and “/SignIn/team” components will be rendered.

That’s excellent if that’s what you had in mind! If this isn’t what you want, you might have to surround this collection of Routes with a Switch. This will enable the rendering of the first path that matches the URL.

2. Package:

React Router v4’s package structure changed so that installing react-router is no longer essential; instead, you must install react-router-dom, but nothing is lost because it re-exports all of react-exports. router’s You must therefore switch any import references to react-router to react-router-dom.

3. History:

Routing relies heavily on history because it helps us remember our past and present locations. React-history router’s can take many different shapes, thus explaining them all would take some time.

So, in order to keep this essay on topic, I’ll just suggest that you read this article that discusses the background of react router 4. The majority of your uses of history should be covered by this article.

4. Redux Integration:

We discovered that in our situation, connecting redux architecture to our router didn’t require the use of a separate library, especially since our primary use case for this — Blocked Updates — was already addressed by react router.

What is Blocked Updates?

The app occasionally fails to update when the location changes. It is known as a “Blocked Update.” If both of these conditions are true, then something may occur:

Through connect(), the component is associated with Redux (Component).
A Route does not render the component.
With these situations, the component’s connect method was wrapped in withRouter.

As a result, the app continues to update as the Redux state changes. This allowed the router information to follow the component when it is linked to.

5. Props:

The props in React supplied through the router and the manner they are accessible have changed in React Router version 4. Three markers are currently passed by the route:

  • History
  • Match

1. History:

I won’t list them all because history also has a lot of additional
attributes and methods, but here are a few that might be most frequently used:
Length: amount of history stack entries.
goBack(): permits you to advance the pointer by 1 entry in the history stack.

2. Match:

Params: obtains the dynamic portions of the path from the URL, for instance if the path is “/Signin/:id”, accessing this in the component. Using props.match.params, you can obtain the id from the URL.

Conclusion

As you have seen, a React router is a powerful and robust library used to create declarative routes. However, a new design pattern will perfectly fit into the previous react version and give an excellent user experience.

At Bosc Tech Labs, we have an experienced React developers team who will help you to understand how to upgrade the react-router in easy and short steps. Feel Free to contact us for your subsequent react app development.

Frequently Asked Questions (FAQs)

1. What are the React Router types?

Based on the part of the URL, the router will use the track content that a user is trying to view. React router offers three various types of routers, and they are Memory, Browser and Hash routers.

2. Why did we utilize a useHistory in React?

useHistroy is one of the well-known hoks that the React Router is offering. It helps you to access a history instance which React Router uses. By using the history instance, you can redirect users to another page.

Issue

element=<((<Home />), (<Header />))>> is actually a Comma Operator expression, which when evaluated returns the value of the last operand, <Header /> in your case.

Solution

To convert the react-router-dom@5 code

to react-router-dom@6 API/syntax, replace the Switch component with the Routes component and move the routed content onto the Route component’s element prop:

If rendering the header component with several routes it is common to create layout routes that render common UI and an Outlet for nested routes to render their element into.

Upgrade to React Router v6

React Router Version 6 is great for TypeScript programmers because it ships with type definitions. Another great feature is the useRoutes hook, which simplifies routing setups in your functional React components. You can also render child components by using the new Outlet API.

Before React Router v6

Prior to React Router v6, you had to install external type definitions along with the React Router packages:

    5.1.9 (optional, because it gets hoisted from @types/react-router-dom ) 5.1.7 5.2.0 5.2.0

This is an example of how routing with React Router v5 was done:

Router component

Route configuration

Route setup separated by layouts. Routes are evaluated in order. The Switch component guarantees that there are only exclusive matches. No other Route definition will be rendered if there is a match. If there is no match, the wildcard route of * will be used to render a page not found view:

Links and Layouts

The main layout shows how to link to different views by using the Link component:

The account layout defines child routes of the application with their respective components. Pay attention to the order of the routes: /account/:id comes last because the :id parameter will match anything after /account and would also match /account/add and others.

Props from routes

If you want to use matching parameters from your routes, you will have to define RouteComponentProps in your React component:

React Router v6

Installation

You don’t need to install additional typings with React Router v6. You will be good by adding just these two packages to your web application:

    6.0.0-beta.0 6.0.0-beta.0

Router

You will have to wrap your main app component in a Router component:

If you don’t follow this rule, you are likely to run into the following error:

Uncaught Error: useRoutes() may be used only in the context of a component.

Nested Routing

When your app is wrapped in a <Router> component, you can define its routes. React Router v6 provides a useRoutes hook to do that:

By looking at the code above, you may have noticed that React Router supports nested routing where you can define routes for different parts of your application with different layouts. This is possible because of the <Outlet /> component, which is a placeholder for the elements that should be rendered on the child routes / paths.

Here is the code of the AccountLayout component to showcase the new Outlet API:

Navigation

Navigation between different views is done with the Link component, which uses navigate under the hood and is the preferred way to make URL navigations. The use of history and useHistory is deprecated and should be replaced with the useNavigate hook. The React Router team provides a Migration Guide in this regard.

Props and match

There is no more need to extend your component’s props with the properties of match . You can retrieve parameters from your routing with the useParams hook:

Как мы переходили на React-router v6: подводные камни и альтернативы

Мы перешли на шестую версии React-router. Это помогло нам решить несколько проблем, например, определение маршрутов в Switch рендерит точный маршрут, а не первое совпадение, а размер бандла уменьшился почти в 2 раза.

В статье расскажем про опыт миграции и подготовительный этап, трудности, возникшие после миграции и ошибки, информации о которых нет в официальной документации, и пути их обхода. Также будет альтернативный способ перехода с помощью официального пакета.

Об авторе:

Андрей Новиков

Старший разработчик Альфа-Банк

Зачем мы перешли, или Что не так с пятым React-router?

Зачем переходить на шестую? Чтобы сидеть и разбираться? Нет, просто с пятой версией были проблемы, которые решены в шестой.

Читать:
Что значат квадратные скобки в математике

#1. При определение маршрутов Switch рендерилось первое совпадение, а не точный маршрут. Чтобы React-router рендерил точный маршрут, как он забит в адресной строке, нужно было либо указывать свойство exact, либо соблюдать точный порядок для вывода нужных компонент.

Например, на левой части картинки мы видим, что если захотим отрендерить, отобразить любой другой компонент с пользователями, например, страницы about или конкретным пользователем, то у нас всегда будет отображаться домашняя страница. Как исправить указано на правой части — переопределить порядок маршрутов или указывать везде свойство exact, что тоже трудоемкий способ.

#2. Метод History.push() в пятой версии перестал запускать навигацию: ряд issue в репозитории GitHub есть до сих пор.

#3. Push и replace сохраняли значения предыдущих search и hash строк. Например, если в адресной строке у нас есть id, то при использовании этих методов мы получим bar с id равным какому-то значению, вместо просто bar. Хотя ожидали, что путь обновится без лишних параметров. По этой проблеме также есть issue, в котором описано, как победить эту проблему, но там также указано, что скорее всего это баг, а не фича библиотеки.

#4. Routes запрашивает пути маршрутов с похожими, а не точными именами. Чтобы решить проблему, мы указывали свойство exact и тогда поведение было корректно.

#5. Долгая сборка и развертывание. Пятая версии до сих пор разрабатывается — недавно вышла версия 5.3.2, в которой появилась поддержка React 18. Это всё сказывалось на размере: сборка и развертывание на клиенте выходила долгой.

Апдейт: Забегая вперед, отмечу, что после перехода, шестая версия у нас весила как 62% предыдущего, а скорость загрузки в несжатом виде на 74 мс меньше.

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

Этапы перехода: подготовительный и миграция

Проанализировав все эти проблемы, наша команда приняла решение, что пора попробовать новую версию и посмотреть, как всё работает под капотом. Мы разбили наш переход на 2 этапа: подготовительный и, непосредственно, сама миграция.

В подготовительный входит 4 шага.

#1. Обновление React до 16.8 и выше, потому что теперь мы используем хуки, а в шестой версии уже убрали всю поддержку старого кода.

#2. Обновление стиля передачи компонента маршрута в children вместо component. Изменился стиль передачи компонента в маршрутах: мы не передаем компоненты в props component или render props. Мы теперь должны передавать в children или как дочерний маршрут. Это облегчит переход на шестой Router, потому что синтаксис будет более похож, в отличии от предыдущей версии.

На картинке пример. Нам было нужно немного поменять стиль, и если раньше мы всегда использовали привычный нам проп компонент (слева), то теперь мы используем children, либо вложенные маршруты.

#3. Удаление <Redirect> в компоненте <Switch> на клиенте. На этом этапе меняем редирект: ставим предыдущий путь в Route path=’’about’’ и уже перенаправляем в пропе render.

#4. Замена <PrivateRoute> на <Route render>. Чтобы приватные маршруты не отображались, когда это не нужно, <PrivateRoute> будет заменен на отдельный компонент, в котором и будет проводиться обработка авторизации. Мы используем пропс element и меняющуюся логику.

В этап миграции входит 5 шагов. Говоря о шестой версии, мы должны изменить пути маршрутов на относительные: то, что мы выносили в дочерние маршруты, выносим в element.

#1. Обновление React-router до 6.2.0+.

#2. Обновление элементов <Switch> на <Routes>.

#3. Относительные маршруты и ссылки. Есть такой способ авторизации на клиенте, когда логику убираем в отдельные функции компоненты. На картинке пример из шестой версии, но нужно понимать отличия от предыдущего, подготовительного, этапа.

Отличия в том, что вместо функции в пропе render используется element. Дочерние маршруты, что уже поменяли на предыдущем этапе, просто перемещаем в проп element.

У нас появилась крутая возможность больше не матчить наши маршруты каждый раз, а задавать относительные пути. Дочерние компоненты смотрят на родительские. Если у родительских есть какой-то путь, то все дочерние будут отображаться в адресной строке относительно предыдущего.

#4. Замена библиотеки react-router-config на хук useRoutes. Для тех проектов, где используется библиотека для объектной нотации, нужно перейти на хук useRoutes, который позволяет также хранить все маршруты в одном месте.

У нас есть приложения, которые использовали дополнительную библиотеку — это react-router-config, позволяла использовать объектную нотацию. Этот способ полезен, когда у нас где-то есть один файл конфигурации, и мы можем даже не использовать JSX- разметку.

#5. useNavigate вместо useHistory. Это самая крутая фича — позволила нам уйти от тех проблем, которые упомянул в начале.

у нас корректно работает push по умолчанию;

если нам нужно использовать другие методы — они передаются вторым параметром, например, просто ставим replace со значением true;

если если что-то нужно добавить в стэйт, это также возможно.

Миграция завершена, но на этом всё не закончилось

На этом наша миграция закончилась и всё прекрасно работало, но как же без трудностей?

На этапе тестирования мы посмотрели наши логи и обнаружили, что сыпятся ошибки о том, что React-router не может отобразить ни один компонент, хотя он прекрасно всё рендерил.

Это было связано с тем, что на наших стендах приложение развёртывалось не в руте, а по определенному контекстному пути (context route), который у нас передается в basename.

Примечание. У нас микрофронтенды. Больше о микрофронтендах можно узнать из нашей статьи Webpack Module Federation: «официальное» решение в микрофронтендах.

Этот Conteхt Route при серверном рендеринге задавался для StaticRouter в проп basename. Оказалось, что указание этого пропа было излишним, в документации информации об этом нет, но при этом ошибка возникает.

Следующая ошибка возникла при переходе на React 18 — мы получали ошибки в консоль при продакшн сборке. Чтобы решить проблемы достаточно было не указывать basename в статик роутере. Приложение корректно работало как с серверным рендерингом, так и без него. Сообщения об ошибках перестали отображаться.

Примечание. Но на клиенте baseName мы оставляем.

Примечание. Если вы уже перешли на эту версию, напишите, возникала ли у вас подобная ошибка.

Минуса нашего подхода в том, что мы делали это всё за раз — это отнимало время на тщательное изучение и тестирование. Но такой способ мы выбрали потому, что раньше мы мигрировали на версию 6.2 и никаких других способов больше не было.

Есть альтернативный способ перехода. Его особенность в том, что команде не нужно за одну итерацию менять всё приложение, а достаточно поэтапно делать изменения, продолжая выпускаться, не останавливая релизный цикл и не блокируя выпуск бизнесовых задач. Этот пакет называется CompatRouter. Появился он с версией 6.3 React-router.

Инкрементная миграция

Как проходит инкрементная миграция по шагам:

Замена <Route> на <CompatRoute> в <Switch>.

Замена кода компонента, используя API v6 вместо v5.

Преобразование <Switch> в <Routes> и <CompatRoute> в <Route>.

Прохождение по компонентам дерева.

Удаление пакета совместимости.

Установка CompatRouter. С версии 6.3 на помощь пришел официальный пакет CompatRouter, который позволяет не делать всё сразу скопом, а переходить поэтапно, оставляя каждое изменение на коммиты.

Во-первых, устанавливаем библиотеку. Установка простая: выполняем команду npm install, импортируем библиотеку и добавляем её перед Switch.

Меняем <Route> на <CompatRoute> в <Switch>. Зачем? Это некая прослойка — позволит использовать одновременно пятую и шестую версии.

В компоненте реализована такая логика:

она смотрит какие проп ей передаются — пятой версии или шестой;

применяет логику версии, например, для пятой логику пятой версии;

Замена кода компонента, используя API v6 вместо v5. Изменяем матчинг на хук useParams, чтобы предоставить необходимые параметры компонента. useHistory меняем на уже знакомый хук useNavigate. Если где-то использовался location props, мы меняем его на useLocation, который также позволяет нам достучаться до нужных свойств локации.

Проходимся по ссылкам и меняем их на относительные. Обновляем абсолютные ссылки, основанные на матчинге, и меняем ссылки на относительные.

Важное изменение — exact в ссылках меняется на end. Вместо пропа для активного класса мы используем свойство isActive, и, уже исходя из этого, рендерим нужный нам стиль.

Активный класс (activeClassName) и стиль (activeStyle) работают по умолчанию для NavLink. Если нужно передать другое имя для активного класса, тогда нужно передать функцию для свойства className. В эту функцию автоматически передается объект, у которого есть ключ isActive, который как раз проверяет активная ссылка или нет. То же самое можно сделать через свойство:

Преобразование <Switch> в <Routes> и <CompatRoute> в <Route>. Поскольку все дочерние компоненты у нас уже заменены на шестую версию и используется такая же версия АПИ, то необходимость в <CompatRoute> тоже исчезает.

Также заменяем всё не в ссылках, а в маршруте, на относительные ссылки. Компоненты передаем вместо component пропсом в элемент.

Прохождение по компонентам дерева. Проверяем, что нигде не забыли заменить пути на относительные в ссылках, и включили ли глубокое сопоставление путей для компонент через символ “*”.

Удаление пакета совместимости. На этом всё, наш переход закончен — мы просто удаляем вспомогательную библиотеку, она больше не требуется.

Примечание. Схема работает при обновлении и с более ранних версий, например, с четвертой или третьей. Но здесь придется намного дольше изучать документацию, потому что накопилось много изменений.

Преимущества и выводы

Мы можем визуализировать иерархию маршрутов с помощью хука useRoutes. Например, можем использовать компонент outlet для вывода этих компонентов в нужном месте.

Теперь порядок маршрутов определений не зависит от того, что будет отрендерено на странице. Мы не загружены лишними реквизитами и гибки в разделении маршрутов между компонентами.

Шестая версия гибка в разделении маршрутов между компонентами и ранжирует маршруты, не загромождая реквизитами компоненты маршрута.

Появление относительных маршрутов и ссылок, реализация полностью на хуках. Процесс перехода занимает мало времени, но при этом код шестой версии намного компактнее. Например, отправка аналитики теперь занимает 10 строк вместо 37.

Вес наших приложений уменьшился, а выпуск — немного ускорился. Мы больше не используем дополнительные библиотеки — всё работает из коробки, что здорово.

Процесс перехода у нас занял не так много времени, но стоит обратить внимание, что новый АПИ требует изучения, что увеличивает время вхождения новых разработчиков. От ошибок в новой версии тоже никто не застрахован.

Также рекомендуем почитать.

​​Подписывайтесь на Телеграм-канал Alfa Digital Jobs — там мы рассказываем про нашу работу (иногда шутки шутим), делимся новостями и полезными советами. Ещё есть Alfa Digital в ВК: постим новости, видео с митапов и недавно выпустили новое шоу «Из бэклога» совместно с Selectel и Space307 про удалёнку, собеседования, трекинг задач, взаимодействие команд, адаптацию новичков, горизонты планирования и конец Slack’а.

Похожие статьи