Каталог статей
Введение в маршрутизацию
обзор
React Router публикуется на npm в трех разных пакетах:
- react-router: основная библиотека роутинга, которая предоставляет многое: компоненты, хуки.
- react-router-dom: Содержит все содержимое react-router и добавляет некоторые компоненты, предназначенные для DOM, такие как
<BrowserRouter>
и т.д. - react-router-native: включите все содержимое react-router и добавьте некоторые API, предназначенные для ReactNative, например:
<NativeRouter>
и т. д.
Разнообразие
Что изменилось по сравнению с версиями React Router 5.x?
-
Изменения встроенных компонентов: удалены
<Switch/>
, добавлены и<Routes/>
т.д. -
Изменения в синтаксисе:
component={About}
изменено наelement={<About/>}
и т.д. -
Добавлено несколько хуков:
useParams
,useNavigate
,useMatch
и т.д. -
Официальная рекомендация — использовать функциональные компоненты
документ
Адрес официального сайта: https://reactrouter.com/
компонент маршрутизации
БраузерРоутер
<BrowserRouter>
Используется для обертывания всего приложения.
import React from "react";
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
{/* 整体结构(通常为App组件) */}
</BrowserRouter>
);
HashRouter
Функция <BrowserRouter>
та же самая, но <HashRouter>
значение хеша в адресной строке изменено.
<HashRouter>
Примечания: Использование , в версии 6.x <BrowserRouter>
такое же, как и в 5.x.
Маршруты 与 Маршрут
Маршруты предназначены для создания менеджера маршрутизации, а Маршрут — для создания объекта маршрутизации.
-
Предыдущий был удален в версии v6
<Switch>
и введена новая замена:<Routes>
. -
<Routes>
И<Route>
для совместного использования, и должны быть<Routes>
упакованы<Route>
. -
<Route>
Эквивалент оператора if, который отображает соответствующий компонент, если его путь соответствует текущему URL-адресу. -
<Route caseSensitive>
Атрибут используется для указания: следует ли учитывать регистр символов (по умолчанию — false). -
Когда URL-адрес изменяется,
<Routes>
все его дочерние элементы просматриваются<Route>
, чтобы найти наилучшее соответствие, и компонент отображается. -
<Route>
Он также может быть вложенным и может использоваться дляuseRoutes()
настройки «таблицы маршрутизации», но он должен отображать свои подмаршруты через<Outlet>
компонент .
<Routes>
{/* path定义路径,可以省略path前的/;element定义当前路径对应的组件 */}
<Route path='/' element={<Home />} />
{/*
路由嵌套:路由嵌套要写在路由配置页,渲染嵌套的路由组件的位置使用Outlet
friend 是一级路由,路径为 /friend
chat是二级路由,对应路径为 /friend/chat/张三
*/}
<Route path='friend' element={<Friends />} />
<Route path='chat/:name' element={<Chat />} />
</Route>
<Route path='setting' element={<Settings />} />
{/* Route也可以不写element属性, 这时就是用于展示嵌套的路由,所对应的路径是/users/login */}
<Route path="user">
<Route path="login" element={<Login />} />
</Route>
{/* 当没有其他路由匹配该URL时,你可以使用path="*"渲染一个"未找到"的路由。这条路由将匹配任何URL,但优先级最低,因此路由器只有在没有其他路由匹配的情况下才会选择它 */}
<Route path='*' element={<NotFound />} />
</Routes>
Связь
<Link>
Измените URL-адрес без отправки сетевого запроса (ссылка маршрутизации).
ПРИМЕЧАНИЕ. <Link>
Снаружи необходимо обернуть <BrowserRouter>
или <HashRouter>
обернуть.
import { Link } from "react-router-dom";
const App = () => {
const [items, setItems] = useState([
{ path: '/', title: '首页', conponent: Home },
{ path: '/friend', title: '好友', conponent: Friends },
{ path: '/setting', title: '设置', conponent: Settings },
]);
return (
<div className='app'>
<nav className='nav'>
<div className='w'>
{items.map(item => (
<Link to={item.path} key={item.path}>
{item.title}
</Link>
))}
</div>
</nav>
</div>
);
};
NavLink
<NavLink>
Подобно компонентам <Link>
, и может достичь эффекта «подсветки» навигации.
-
NavLink组件
Функции иLink组件
одинаковы, разница в том, что можно судитьto属性
о том, является ли это текущим совпадающим маршрутом. -
NavLink组件
Или он может получить функцию, функция получает параметр, стильstyle
может быть настроен в соответствии с параметром, и можно обрабатывать состояние выделения.Имя класса по умолчанию NavLink активно, и выделение может быть реализовано путем настройки класса. имя или стиль:className
isActive
-
пользовательское имя класса
<NavLink className={({ isActive }) => (isActive ? 'active' : '')} to={item.path} key={item.path}>
{item.title}
</NavLink>
- нестандартный стиль
<NavLink style={({ isActive }) => ({backgroundColor: isActive ? 'lightblue': ''})} to={item.path} key={item.path}>
{item.title}
</NavLink>
По умолчанию, когда подкомпоненты Home успешно сопоставлены, навигация Home также будет выделена.
При добавлении конечного атрибута в NavLink, если подкомпоненты Home успешно сопоставлены, навигация Home не будет выделена.
<NavLink to="home" end >home</NavLink>
Навигация
Всякий раз, когда <Navigate>
компонент визуализируется, путь изменяется, а представление переключается (перенаправляется).
<Navigate>
Свойство используется replace
для управления режимом перехода (нажать или заменить, по умолчанию — нажимать).
import { useState } from 'react';
import { Navigate } from 'react-router-dom';
const Home = props => {
const [show, setShow] = useState(false);
return (
<div id='home' className='w'>
<h1>首页</h1>
{/* 根据show的值决定是否切换视图 */}
{show && <Navigate to='/setting' replace={true} />}
<button onClick={() => setShow(true)}>按钮</button>
</div>
);
};
Выход
При <Route>
создании вложенности визуализируются соответствующие последующие подмаршруты.
import { useState } from 'react';
import { NavLink, Outlet } from 'react-router-dom';
const Friends = props => {
const [items, setItems] = useState([
{ name: 'Tom', id: 10 },
{ name: 'Lily', id: 11 },
{ name: 'Lucy', id: 12 },
]);
return (
<div id='home' className='w'>
<nav className='nav-home'>
{items.map(item => {
return (
<NavLink className={({ isActive }) => (isActive ? 'active link' : 'link')} to={'/friend/chat/' + item.name} key={item.id}>
{item.name}
</NavLink>
);
})}
</nav>
{/* Outlet 渲染子路由组件 */}
<Outlet className='child'></Outlet>
</div>
);
};
Хуки маршрутизации
использовать маршруты ()
<Routes>
Функция: Создавать и динамически в соответствии с таблицей маршрутизации <Route>
. Его роль заключается в динамической настройке маршрутов, он получает массив маршрутов и использует сопоставленные маршруты для отображения соответствующих компонентов.
useRoutes()
Функционально эквивалентен <Routes>
, но использует объекты JavaScript вместо элементов для определения маршрутов. Эти объекты имеют те же свойства, что и <Route>
компоненты .
useRoutes()
Возвращаемое значение — допустимый элемент React, который можно использовать для визуализации дерева маршрутизации.
//路由表配置:src/routes/index.jsx
import { Navigate } from 'react-router-dom';
import Home from '../views/Home';
import Friend from '../views/Friend';
import Setting from '../views/Setting';
import NotFound from '../views/NotFound';
import Chat from '../views/Chat';
const routes = [
{ path: '/', element: <Navigate to='/home' /> },
{ path: '/home', element: <Home /> },
{
path: '/friend',
element: <Friend />,
children: [{ path: 'chat/:name', element: <Chat /> }],
},
{ path: '/setting', element: <Setting /> },
{ path: '*', element: <NotFound /> },
];
export default routes;
// App.jsx
import { useState } from 'react';
import { NavLink, useRoutes } from 'react-router-dom';
import routes from './routes';
const App = () => {
// 根据路由表生成对应的路由规则
const ElementRouter = useRoutes(routes)
const [items] = useState([
{ path: '/home', title: '首页' },
{ path: '/friend', title: '好友' },
{ path: '/setting', title: '设置' },
]);
return (
<div className='app'>
<nav className='nav'>
<div className='w'>
{items.map(item => (
<NavLink className={({ isActive }) => (isActive ? 'active' : '')} to={item.path} key={item.path}>
{item.title}
</NavLink>
))}
</div>
</nav>
{/* 注册路由 */}
{ElementRouter}
</div>
);
};
использоватьNavigate()
Роль: возвращает функцию, используемую для реализации программной навигации.
import { useNavigate } from 'react-router-dom';
function Chat(props) {
const navigate = useNavigate();
const goBack = () => {
// 第一种使用方式:传入数值进行前进或后退,类似 history.go()方法
// navigate(-1);
// 第二种使用方式:指定具体的路径
navigate('/friend', {
replace: false,
state: { a: 1, b: 2 },
});
};
return (
<div id="chat" className="w">
<h2>chat页面 </h2>
<button onClick={goBack}>返回</button>
</div>
);
}
использоватьпараметры()
Функция: вернуть params
параметры текущего соответствующего маршрута.
import { useParams, useNavigate, useLocation } from 'react-router-dom';
function Chat(props) {
// 获取路径参数
const params = useParams();
return (
<div id='chat' className='w'>
<h2>chat页面</h2>
<p>params.name: {params.name}</p>
</div>
);
}
const App = () => {
return (
<div className='app'>
<Routes>
<Route path='chat/:name' element={<Chat />} />
</Routes>
</div>
);
};
использоватьместоположение()
location
Функция: получение информации о текущем местоположении и сравнение свойств компонента маршрутизации в версии 5.x.
import { useLocation } from 'react-router-dom';
function Friend(props) {
// 路由位置信息
const location = useLocation();
console.log(location);
// {
// hash: "",
// key: "1nw4p3qf",
// pathname: "/friend",
// search: "?name=张三&age=18",
// state: {a: 1, b: 2},
// }
return (
<div id='friend' className='w'>
<h2>friend页面</h2>
</div>
);
}
использоватьпараметры поиска()
Роль: используется для чтения и изменения строки запроса в URL-адресе текущего местоположения.
Возвращает массив, содержащий два значения: текущий параметр поиска и функцию для обновления поиска.
function Chat(props) {
const [search, setSearch] = useSearchParams();
const name = search.get('name');
const age = search.get('age');
return (
<div id='chat' className='w'>
<h2>chat页面</h2>
<button onClick={() => setSearch('name=张三&age=18')}>点击更新一下收到的search参数</button>
<p> name={name} </p>
<p> age={age} </p>
</div>
);
}
использовать матч()
match
Функция: вернуть текущую информацию о совпадении и сравнить свойства компонента маршрутизации в версии 5.x.
<Route path="/friend/chat/:name" element={<Chat />}/>
<NavLink to="/friend/chat/Tom">好友</NavLink>
function Chat(props) {
const match = useMatch('/friend/chat/:name');
console.log(match);
// {
// params: { name: 'Tom' },
// pathname: "/friend/chat/Tom",
// pathnameBase: "/friend/chat/Tom",
// pattern: {path: '/friend/chat/:name', caseSensitive: false, end: true},
// }
return (
<div id='chat' className='w'>
<h2>chat页面</h2>
</div>
);
}
использоватьInRouterContext()
Роль: если компонент рендерится в <Router>
контексте useInRouterContext
хука, возвращает true, иначе возвращает false.
использоватьNavigationType()
Функция: вернуть текущий тип навигации (как пользователь попал на текущую страницу).
Возвращаемое значение: POP
, PUSH
, REPLACE
.
Примечания: POP
Это означает, что компонент маршрутизации открывается прямо в браузере (обновите страницу).
использоватьOutlet()
Роль: используется для визуализации вложенных маршрутов, отображаемых в текущем компоненте.
const result = useOutlet()
console.log(result)
// 如果嵌套路由没有挂载,则result为null
// 如果嵌套路由已经挂载,则展示嵌套的路由对象
использоватьResolvedPath()
Функция: учитывая значение URL, анализировать значение: путь, поиск, хэш.
Шаги маршрутизации
Шаг 1: Установите
react-router-dom — это библиотека, основанная на библиотеке react-router на стороне браузера, поэтому после ее установки вам не нужно вручную устанавливать react-router
npm install react-router-dom
Шаг 2: Подключите маршрутизатор
Свяжите свое приложение с URL-адресом браузера. Оберните BrowserRouter вокруг вашего приложения
// main.jsx
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
Шаг 2: Настройка таблицы маршрутизации
//路由表配置:src/routes/index.jsx
import { Navigate } from 'react-router-dom';
import Home from '../views/Home';
import Friend from '../views/Friend';
import Setting from '../views/Setting';
import NotFound from '../views/NotFound';
import Chat from '../views/Chat';
const routes = [
// Navigate 重定向
{ path: '/', element: <Navigate to='/home' /> },
{ path: '/home', element: <Home /> },
{
path: '/friend',
element: <Friend />,
children: [{ path: 'chat/:name', element: <Chat /> }],
},
{ path: '/setting', element: <Setting /> },
{ path: '*', element: <NotFound /> },
];
export default routes;
Шаг 4. Зарегистрируйте маршрутизацию и настройте ссылки маршрутизации
Прописывайте маршруты в src/App.jsx
, добавляйте ссылки и глобальную навигацию.
// App.jsx
import { useState } from 'react';
import './App.css';
import { NavLink, useRoutes } from 'react-router-dom';
import routes from './routes';
const App = () => {
// 根据路由表生成对应的路由规则
const ElementRouter = useRoutes(routes);
const [items] = useState([
{ path: '/home', title: '首页' },
{ path: '/friend', title: '好友' },
{ path: '/setting', title: '设置' },
]);
return (
<div className='app'>
<nav className='nav'>
<div className='w'>
{/* 路由链接 */}
{items.map(item => (
<NavLink className={({ isActive }) => (isActive ? 'active' : '')} to={item.path} key={item.path}>
{item.title}
</NavLink>
))}
</div>
</nav>
{/* 注册路由 */}
{ElementRouter}
</div>
);
};
export default App;
Шаг 5: Создайте компонент маршрутизации
Компоненты маршрутизации помещаются в файл представлений или страниц в каталоге src.
Настройка маршрутизации с компонентами
import { NavLink, Route, Routes } from 'react-router-dom';
import Chat from './views/Chat';
import Friend from './views/Friend';
import Home from './views/Home';
import NotFound from './views/NotFound';
import Setting from './views/Setting';
const App = () => {
const items = [
{ path: '/', title: '首页' },
{ path: '/friend', title: '好友' },
{ path: '/setting', title: '设置' },
];
return (
<div className='app'>
<nav className='nav'>
<div className='w'>
{items.map(item => (
<NavLink className={({ isActive }) => (isActive ? 'active' : '')} to={item.path} key={item.path}>
{item.title}
</NavLink>
))}
</div>
</nav>
<Routes>
<Route path='/' element={<Home />} />
<Route path='friend' element={<Friend />}>
<Route path='chat/:name' element={<Chat />} />
</Route>
<Route path='setting' element={<Setting />} />
<Route path='*' element={<NotFound />} />
</Routes>
</div>
);
};
export default App;
маршрут по умолчанию
Маршрут по умолчанию реализован с использованием атрибута index.
Разница между индексным маршрутом и другими маршрутами заключается в том, что он не имеет атрибута пути и использует тот же путь, что и родительский маршрут.
- Индексный маршрут отображается на выходе из родительского маршрута, а адрес маршрута совпадает с адресом родительского маршрута.
- Индексный маршрут совпадает, когда родительский маршрут совпадает, а другие дочерние маршруты не совпадают.
- Индексный маршрут является дочерним узлом по умолчанию для родительского узла.
- Индексный маршрут отображается, когда пользователь еще не щелкнул ссылку в навигации.
const routes = [
{
path: '/setting',
element: <Setting />,
children: [
{ index: true, element: <Other1 /> },
{ path: 'other1', element: <Other1 /> },
{ path: 'other2', element: <Other2 /> },
],
},
];
import { Link,Outlet } from "react-router-dom";
const Settings = props => {
return (
<div id='settings' className='w'>
<h1>设置</h1>
<Link to='/setting/other1'>选项1</Link>
<Link to='/setting/other2'>选项2</Link>
<Outlet className='child'></Outlet>
</div>
);
};
export default Settings;
- Когда путь
/setting
равен , Outlet в компоненте Setting отобразитOther1
компонент - Когда путь
/setting/other1
равен , Outlet в компоненте Setting отобразитOther1
компонент - Когда путь
/setting/other2
равен , Outlet в компоненте Setting отобразитOther2
компонент
мониторинг маршрута
import { useLocation } from 'react-router-dom';
// 监听路由的变化
const location = useLocation();
useEffect(() => {
console.log('进入:', location.pathname);
return () => {
console.log('离开:', location.pathname);
};
});
Параметры маршрутизации
параметр params
реагирующая маршрутизация поддерживает динамическую маршрутизацию
// 路由表
const routes = [
{
path: 'chat/:name',
element:<Chat/>,
},
];
<Link to='/chat/张三'>张三</Link>
Получить параметры с помощью useParams
import { useParams } from 'react-router-dom';
// 获取路径参数
const params = useParams();
params // {name: '张三'}
параметр поиска
// 路由表
const routes = [
{
path: 'chat',
element: <Chat/>,
},
];
<Link to='/chat/?name=张三'>张三</Link>
Получить параметры с помощью useSearchParams
import { useSearchParams } from 'react-router-dom';
const [search, setSearch] = useSearchParams();
const name = search.get('name'); // 张三
Или используйте useLocation
import { useLocation } from 'react-router-dom';
import qs from "query-string";
const { search } = useLocation();
console.log(qs.parse(location.search)); // {name: '张三'}
Примечания: Поиск, полученный с помощью useLocation, представляет собой закодированную строку с urlencoded (например: ?age=20&name=zhangsan), которую необходимо преобразовать в объект с помощью строки запроса.
атрибут состояния
Передать параметры через свойство состояния Link
// 路由表
const routes = [
{
path: 'chat',
element: <Chat/>,
},
];
<Link to='/chat' state={ {name:'张三'} }>张三</Link>
Получить параметры с помощью useLocation
import { useLocation } from 'react-router-dom';
let { state } = useLocation();
state // {name: '张三'}
программная навигация
Программная навигация с использованием useNavigate
import { useNavigate } from "react-router-dom";
export default function Demo() {
const navigate = useNavigate();
//...
}
push-навигация
- push jump + параметр переноса параметров
navigate(`/child/${id}/${title}`);
- push jump + перенос параметров поиска
navigate(`/child?id=${id}&title=${title}`);
- push jump + перенос параметров состояния
navigate("/child", { state: { id, title }});
заменить навигацию
- заменить прыжок + параметр переноса параметров
navigate(`/child/${id}/${title}`,{replace: true});
- заменить прыжок + перенести параметры поиска
navigate(`/b/child?id=${id}&title=${title}`,{replace: true});
- заменить параметры состояния перехода + переноса
navigate("/child", { state: { id, title },replace: true});
Маршрутизация ленивой загрузки
- React использует React.lazy и import() для динамической загрузки во время рендеринга.
- Используйте приостановку, чтобы решить проблему отображения страницы при асинхронной загрузке ресурсов.
- Динамически импортировать компоненты, требующие ленивой загрузки, через API lazy().
- Импортированные компоненты в настоящее время поддерживают экспорт только в формате по умолчанию.
- Приостановка оборачивает лениво загруженные компоненты для загрузки, и вы можете установить резервный вариант, чтобы реализовать эффект загрузки.
- React.lazy можно комбинировать с Router для ленивой загрузки модулей.
React.Suspense
React.lazy
достичь с
React.suspense
Загрузочный карман для реализации ленивой маршрутизации загрузки
<Suspense fallback={<Loading />}>
<SomeComponent />
</Suspense>
fallback
Параметры можно передавать в компонентах реакции или элементах dom, например:<div>Loading...</div>
- Примечание.
React.suspense
Не только для маршрутов с отложенной загрузкой, но и для всех компонентов с отложенной загрузкой, пока существует отложенная загрузка, они могут быть реализованыReact.suspense
с помощьюloading
или других средств .占位dom
React.lazy
Используется для переноса путей компонентов для реализации ленивой загрузки маршрутов.
const LazyDemoPage = lazy(() => import("@views/DemoPage"));
- Примечание.
React.lazy
В настоящее время поддерживается только экспорт по умолчанию.
случай:
//路由表配置:src/routes/index.jsx
import { lazy, Suspense } from 'react';
const Chat = lazy(() => import('@/views/Chat'));
const Friend = lazy(() => import('@/views/Friend'));
const Home = lazy(() => import('@/views/Home'));
const Setting = lazy(() => import('@/views/Setting'));
const NotFound = lazy(() => import('@/views/NotFound'));
const LoadingTip = Element => (
<Suspense fallback={<div>loading...</div>}>
<Element />
</Suspense>
);
const routes = [
{ path: '/', element: LoadingTip(Home) },
{
path: '/friend',
element: LoadingTip(Friend),
children: [
{
path: 'chat/:name',
element: LoadingTip(Chat),
},
],
},
{ path: '/setting', element: LoadingTip(Setting) },
{ path: '*', element: LoadingTip(NotFound) },
];
export default routes;
перехват маршрута
таблица маршрутизации
//路由表配置:src/routes/index.jsx
import { lazy, Suspense } from 'react';
const Chat = lazy(() => import('@/views/Chat'));
const Friend = lazy(() => import('@/views/Friend'));
const Home = lazy(() => import('@/views/Home'));
const Login = lazy(() => import('@/views/Login'));
const NotFound = lazy(() => import('@/views/NotFound'));
const LoadingTip = Element => (
<Suspense fallback={<div>loading...</div>}>
<Element />
</Suspense>
);
const routes = [
{
path: '/',
element: LoadingTip(Home),
meta: {
title: '首页',
auth: false,
menu: true,
},
},
{
path: '/friend',
element: LoadingTip(Friend),
meta: {
title: '好友',
auth: true,
menu: true,
},
children: [
{
path: 'chat/:name?',
element: LoadingTip(Chat),
meta: {
title: '聊天',
auth: true,
menu: true,
},
},
],
},
{
path: '/login',
element: LoadingTip(Login),
meta: {
title: '登录',
auth: false,
menu: true,
},
},
{
path: '*',
element: LoadingTip(NotFound),
meta: {
title: '404',
auth: false,
menu: false,
},
},
];
export default routes;
Функция перехвата
//路由表配置:src/routes/routerBefore.jsx
import { Navigate, useLocation, useRoutes } from 'react-router-dom';
import routes from './index';
// 拦截组件
const RouterBeforeEach = props => {
if (props?.route?.meta?.title) {
document.title = props.route.meta.title;
}
const isLogin = !!localStorage.getItem('token');
if (props?.route?.meta?.auth) {
if (!isLogin) {
return <Navigate to={'/login'} replace />;
}
}
const location = useLocation();
const routerKey = location.pathname;
if (isLogin && ['/login'].includes(routerKey)) {
return <Navigate to={'/'} replace />;
}
return <div>{props.children}</div>;
};
// 渲染路由
const renderRoutes = routes => {
return routes.map(item => {
const route = { meta: item.meta, path: item.path };
route.element = <RouterBeforeEach route={item}>{item.element}</RouterBeforeEach>;
if (item.children) {
route.children = renderRoutes(item.children);
}
return route;
});
};
export default function Router() {
return useRoutes(renderRoutes(routes));
}
зарегистрировать маршрут
// App.jsx
import NavBar from './components/NavBar';
import Router from './routes/routerBefore';
const App = () => {
return (
<div className='app'>
<NavBar></NavBar>
{/* 注册路由 */}
{/* {Router()} */}
<Router></Router>
</div>
);
};
export default App;
другой
Лучшая практика защиты маршрутизации react-router v6!
Как в react-router v6 реализована динамическая маршрутизация? - Наггетс (juejin.cn)
Базовое использование React routerV6 и перехват маршрутизации — Zhihu (zhihu.com)