Переход на React Router v6: полное руководство
Чтобы перейти с React Router v5 на v6, вам нужно либо создать новый проект, либо обновить существующий с помощью npm. React Router v6 также широко использует React Hooks, для чего требуется React v16.8 или выше.
В этой статье мы рассмотрим проблемы с React Router v5, что изменилось, как перейти на v6 и какие преимущества предлагает это обновление. Чтобы продолжить, вы должны быть знакомы с React Router.
Проблемы с React Router v5
Содержание статьи:
React Router v5 был близок к совершенству, но все же были некоторые недостатки. Во-первых, history.push() не запускает навигацию; было замечено, что history.push() обновляет URL-адрес браузера, но не переходит по указанному пути. Узнайте больше о проблеме здесь.
Следующее, push и replace, сохраняют предыдущие search и hash строки. Когда метод push или replace выполняется в history, search и hash строки из предыдущих маршрутов остаются в новом маршруте. Узнайте больше о проблеме здесь.
React JS. Основы
Изучите основы ReactJS на практическом примере по созданию учебного веб-приложения
Получить курс сейчас!
Другая проблема заключается в том, что Routes запрашивает пути маршрутов с наиболее похожими именами, а не с точными именами. Например, имя маршрута /test все равно будет вызываться, если маршрут браузера — /, /t, /te, /tes или /test, что неверно. Разработчики должны указать свойство точно, чтобы строго запрашивать имена маршрутов.
Наконец, определение маршрутов с одним и тем же путем, но с необязательными параметрами, требует специальных мер. Например, при определении маршрута /games и другого маршрута с таким же именем, обязателен параметр /games/:id. Разработчикам необходимо упорядочить определение таким образом, чтобы маршрут с параметром был первым, иначе маршруты не будут работать должным образом.
JavaScript // The correct way: Here ‘/games’ will render ‘Games’ component but not ‘SelectedGame’, because it does not have a parameter ‘id’. While ‘/games/:id’ will render only the ‘selectedGame’ component <Router> <Route path=”/games/:id” component={SelectedGame} /> <Route path=”/games” component={Games} /> </Router> // The wrong way: Here either ‘/games’ or ‘/games/:id’ will render the ‘Games’ components <Router> <Route path=”/games” component={Games} /> <Route path=”/games/:id” component={SelectedGame} /> </Router>
1234567891011 | // The correct way: Here ‘/games’ will render ‘Games’ component but not ‘SelectedGame’, because it does not have a parameter ‘id’. While ‘/games/:id’ will render only the ‘selectedGame’ component<Router> <Route path=”/games/:id” component={SelectedGame} /> <Route path=”/games” component={Games} /></Router> // The wrong way: Here either ‘/games’ or ‘/games/:id’ will render the ‘Games’ components<Router> <Route path=”/games” component={Games} /> <Route path=”/games/:id” component={SelectedGame} /></Router> |
Приведенный выше фрагмент кода иллюстрирует правильный и неправильный способ упорядочения маршрутов, связанных путями или параметрами. Первый пример является наиболее подходящим порядком, в то время как второй пример позволяет отображать только маршрут /games для любой ситуации, где /games имеет параметр.
Рассмотрев проблемы с React Router v5, теперь мы обсудим, как выполнить миграцию и что изменилось в React Router v6.
Переход на React Router v6
В следующих разделах вы узнаете, как выполнить обновление до React Router v6 в проектах, где React Router уже установлен, и как выполнить реализацию React Router v6 с нуля.
Обновление React Router в проекте, где он уже установлен
Чтобы обновить версию React Router, откройте терминал и перейдите в каталог проекта, в котором вы хотите его обновить. Для просмотра списка зависимостей проекта, используйте следующую команду: — Вы должны увидеть такой список:
Хотя сгенерированный список может отличаться от приведенного выше, если у вас установлен React Router, вы должны увидеть его последнюю версию. Затем выполните следующую команду, чтобы начать обновление:
JavaScript npm install react-router-dom@latest
1 | npm install react-router-dom@latest |
Если вы выполните эту команду без подключения к Интернету, произойдет сбой, потому что некоторые файлы должны быть загружены во время установки. Если все в порядке, вы должны увидеть нечто подобное; в нашем случае самая последняя версия — v6.0.2:
Если все пойдет хорошо, мы должны увидеть, что React Router был обновлен, когда мы снова запустим команду :
Установка React Router с нуля
Сначала откройте терминал в каталоге проекта, где пока не установлен React Router. Чтобы установить определенную версию React Router, запустите:
JavaScript npm install react-router-dom@[VERSION_TO_BE_INSTALLED]
1 | npm install react-router-dom@[VERSION_TO_BE_INSTALLED] |
Замените [VERSION_TO_BE_INSTALLED] версией, которую вы хотите установить. Затем запустите следующий код, чтобы установить новейшую версию:
JavaScript npm install react-router-dom
1 | npm install react-router-dom |
Эта установка также требует использования Интернета. Если установка прошла успешно, вы должны увидеть что-то похожее на это:
Что изменилось?
Важно знать, что изменилось, чтобы понять, почему обновление до React Router v6 полезно. Обратите внимание, что в определенных обстоятельствах разработчики могут понизить версию программы, чтобы расширить функциональность или избежать проблем.
Мы рассмотрим изменения в React Router v5, о которых следует подумать при выборе версии для реализации в проекте.
Настройка маршрутов
У нас было около трех разных методов генерации маршрутов в React Router v5, что вызывало путаницу. Первый метод заключается в передаче компонента и пути в качестве prop компонента Route:
JavaScript <Route path=”/games” component={Games} />
1 | <Route path=”/games” component={Games} /> |
Это работает хорошо, однако мы не можем передать props визуализированому компоненту. Второй — передать компонент как дочерний элемент компонента Route:
JavaScript <Route path=”/games”> <Games count=”10″ category=”Action” /> </Route>
123 | <Route path=”/games”><Games count=”10″ category=”Action” /></Route> |
Используя этот подход, мы можем передавать пользовательские props компоненту, который хотим визуализировать. Третий и последний метод заключается в использовании render prop, когда функция возвращает компонент для рендеринга:
JavaScript <Route path=”/games” render={(props) => <Games {…props} />} />
1 | <Route path=”/games” render={(props) => <Games {…props} />} /> |
Это также работает и позволяет нам добавлять props к компоненту, который мы визуализируем. Однако оно неоднозначно и склонно к неточностям.
В React Router v6 маршруты были упрощены до такой степени, что нам больше не нужно использовать Switch для запросов маршрутов. Вместо этого мы используем «обязательный» компонент Routes, который ищет маршруты только по имени. Символ * можно использовать для запроса с использованием wildcard.
Затем мы передаем компонент для рендеринга компоненту Route в качестве props элемента. Мы также можем предоставить пользовательские props для компонентов в каждом маршруте, который мы хотим отобразить. Фрагменты кода ниже демонстрируют, как определять маршруты в v6:
JavaScript <Routes> <Route path=”/games” element={<Games />} /> <Route path=”/movies” element={<Movies genre=”Action” age=”13″ />} /> </Routes>
1234 | <Routes> <Route path=”/games” element={<Games />} /> <Route path=”/movies” element={<Movies genre=”Action” age=”13″ />} /></Routes> |
Вы также можете использовать useRoutes для запроса маршрутов в приложении. Для этого мы должны изменить содержимое index.js, где мы меняем враппер App с React.StrictMode на BrowserRouter, как показано ниже:
React JS. Основы
Изучите основы ReactJS на практическом примере по созданию учебного веб-приложения
Получить курс сейчас!
JavaScript import React from ‘react’; import ReactDOM from ‘react-dom’; import App from ‘./App’; import { BrowserRouter } from ‘react-router-dom’ ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById(‘root’) );
12345678910 | import React from ‘react’;import ReactDOM from ‘react-dom’;import App from ‘./App’;import { BrowserRouter } from ‘react-router-dom’ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById(‘root’)); |
Затем в файле App.js мы определяем маршруты, выполнив следующие действия:
JavaScript import { Outlet, useRoutes } from ‘react-router-dom’; const App = () => { let routes = useRoutes([ { path: ‘/’, element: <div>Hello Index</div> }, { path: ‘games’, element: <Games />, children: [ { path: ”, element: <div>Games Index</div> }, { path: ‘:id’, element: <div>Game Details</div> } ] } ]); return routes; } export default App const Games = () => { return ( <div className=”Games”> <div>This is the Games pages</div> <Outlet /> </div> ); }
123456789101112131415161718192021222324252627282930313233 | import { Outlet, useRoutes } from ‘react-router-dom’;const App = () => { let routes = useRoutes([ { path: ‘/’, element: <div>Hello Index</div> }, { path: ‘games’, element: <Games />, children: [ { path: ”, element: <div>Games Index</div> }, { path: ‘:id’, element: <div>Game Details</div> } ] }]); return routes;}export default Appconst Games = () => { return ( <div className=”Games”> <div>This is the Games pages</div> <Outlet /> </div> );} |
Здесь мы импортировали Outlet и useRoutes. useRoutes позволяет нам определять маршруты как массив объектов, в которых мы можем указать path. element будет отображаться при просмотре path. Outlet помогает нам отображать дочерний маршрут, соответствующий текущему path.
Перенаправить на другой маршрут
В React Router v5 мы используем useHistory() для перенаправления, и, как упоминалось ранее, с этим методом были проблемы. Для реализации перенаправления мы обычно делаем следующее:
JavaScript import { useHistory } from “react-route-dom”; const App = () => { const history = useHistory(); const handleClick = () => { history.push(“/home”) } return ( <div> <button onClick={handleClick}>Go Home</button> </div> ) } export default App
1234567891011121314 | import { useHistory } from “react-route-dom”; const App = () => { const history = useHistory(); const handleClick = () => { history.push(“/home”) } return ( <div> <button onClick={handleClick}>Go Home</button> </div> ) }export default App |
В v6 мы используем useNavigate следующим образом:
JavaScript import { useNavigate } from “react-router-dom”; const App = () => { const navigate = useNavigate(); const handleClick = () => { navigate(“/home”); } return ( <div> <button onClick={handleClick}>Go Home</button> </div> ); } export default App
1234567891011121314 | import { useNavigate } from “react-router-dom”; const App = () => { const navigate = useNavigate(); const handleClick = () => { navigate(“/home”); } return ( <div> <button onClick={handleClick}>Go Home</button> </div> );}export default App |
Узнайте больше о перенаправлении с помощью useNavigate вместо useHistory.
В v5 при применении точного пути или маршрута мы используем exact prop. Для реализации делаем следующее:
JavaScript <NavLink to=”/index” exact>Go Home</NavLink>
1 | <NavLink to=”/index” exact>Go Home</NavLink> |
В v6 мы используем end prop для обеспечения точных маршрутов:
JavaScript <NavLink to=”/index” end>Go Home</NavLink>
1 | <NavLink to=”/index” end>Go Home</NavLink> |
В React Router v5 мы используем props activeClassName или activeStyle для стилизации NavLink, который в данный момент активен. Например:
JavaScript <NavLink to=”/home” style={{color: ‘black’}} activeStyle={{color: ‘blue’}} className=”nav_link” activeClassName=”active” >Go Home</NavLink>
1 | <NavLink to=”/home” style={{color: ‘black’}} activeStyle={{color: ‘blue’}} className=”nav_link” activeClassName=”active” >Go Home</NavLink> |
В v6 теперь мы можем использовать функцию с аргументом isActive для определения стиля или className, которые будут использоваться для активного NavLink. Например:
JavaScript <NavLink to=”/home” style={({isActive}) => ({color: isActive ? ‘blue’ : ‘black’})} className={({isActive}) => `nav_link${isActive ? ” active” : “”}`} >Go Home</NavLink>
1 | <NavLink to=”/home” style={({isActive}) => ({color: isActive ? ‘blue’ : ‘black’})} className={({isActive}) => `nav_link${isActive ? ” active” : “”}`} >Go Home</NavLink> |
Использование useMatch вместо useRouteMatch
В v5 useRouteMatch использовался для создания относительных путей подмаршрутов, которые соответствовали определенному маршруту.
В v6 мы используем для этого useMatch. Использование хука useMatch требует паттерн как аргумент и не принимает паттерн в виде массива.
Что было удалено?
В React Router v6 некоторые функции больше не поддерживаются либо из-за неоднозначности, либо из-за ошибок. На данный момент было обнаружено, что две функции были удалены:
Во-первых, usePrompt использовался для подтверждения того, что пользователь хочет выйти со страницы, когда страница находится в состоянии, не требующем выхода пользователя.
Во-вторых, useBlocker похож на usePrompt и использовался для предотвращения ухода пользователей с определенной страницы.
Эти две функции похожи и имеют одну и ту же проблему. В ситуации, когда пользователь пытается выйти из страницы, а навигация ограничена либо usePrompt, либо useBlocker, путь URL-адреса изменяется, даже если навигация запрещена.
Хотя были проблемы с useBlocker и usePrompt, создатели все еще рассматривают возможность их возвращения в v6 после выпуска стабильной версии. Посмотрите здесь для более подробной информации.
Преимущества React Router v6 по сравнению с v5
Бессмысленно мигрировать, если одна версия не предлагает никаких преимуществ перед другой. В этом разделе мы поговорим о преимуществах перехода с React Router v5 на v6.
Одним из наиболее важных соображений для разработчиков является переносимость приложения. Размер React Router v6 был значительно уменьшен по сравнению с предыдущими версиями. Разница между v5 и v6 составляет около 60 процентов. Вот сравнение из Bundlephobia:
Компиляция и развертывание приложений станут проще и быстрее благодаря уменьшению размера. Кроме того, большинство изменений в React Router v6, которые мы рассмотрели, более полезны и вызывают меньше проблем.
Как упоминалось ранее, React Router v6 позволяет маршрутам принимать компоненты в качестве элементов при построении маршрутов и передавать пользовательские props компонентам. Мы также можем вкладывать маршруты и использовать относительные ссылки. Это помогает нам предотвратить или сократить определение новых маршрутов внутри различных файлов компонентов, а также упрощает передачу глобальных данных компонентам и props.
При перенаправлении вместо использования useHistory (у которого были проблемы с обновлением URL-адреса) новый подход с использованием useNavigate был разработан для решения проблемы избыточного URL-адреса. Это позволяет нам установить новый маршрут вручную (navigate(«/home»)) вместо обновления устаревших маршрутов (history.push(«/home»)), что может быть немного двусмысленным.
Наконец, навигационная ссылка NavLink позволяет нам обусловливать активные ссылки, что делает наш код более аккуратным и простым. Вместо того, чтобы передавать два отдельных props для активного и неактивного состояния. Используя NavLink, мы можем легко использовать тернарный оператор, чтобы указать, какой стиль будет затронут, когда ссылка активна или нет.
Заключение
Я надеюсь, что после прочтения этой статьи вы сможете обновить свою версию React Router и реструктурировать свои кодовые базы, чтобы без проблем работать с React Router v6.
Не только React Router v5 должен быть обновлен до v6, но и Reach Router также должен быть переключен на v6.
Регулярно обновляйте React Router v6 и просматривайте документацию на предмет любых изменений, чтобы быть в курсе новых выпусков.
Автор: Joel Adewole
Источник: webformyself.com