По внезапной прихоти на прошлой неделеreact-routerгитхаб посмотрел, молодец, пришла последняя версия(Выпущено 2021.11.46.0.0Официальная версия), и все переписано с ts (представляющим похвалу!!), конкретные изменения можно увидетьMigrating React Router v5 to v6. Я не знаю, не вижу ли я этого, но я был поражен, когда увидел это, и обнаружил, что изменения были довольно большими.6.0.0-beta.8
api
Он также стал проще в использовании, чем раньше. Затем я постараюсь предоставить различные примеры, чтобы представить некоторые часто используемыеapi
изменения, чтобы все были более знакомы с последним использованием.
все изменено на
а такжеSwitch
в сравнении с,Routes
Основные преимущества:
-
Routes
все внутри<Route>
а также<Link>
является относительным. Это делает<Route path>
а также<Link to>
Более компактный и предсказуемый код в - Маршруты выбираются на основе наилучшего совпадения, а не по порядку
- Маршруты могут быть вложены в одном месте, а не разбросаны по разным компонентам (конечно, их можно прописать и в подкомпонентах), а вложенные родительские маршруты
path
нет необходимости добавлять*
import {
BrowserRouter,
Routes,
Route,
Link,
Outlet
} from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
{* 上面的优点一:path是相对的 *}
{* 上面的优点三:path 不用加'*' *}
<Route path="users" element={<Users />}>
{* 上面的优点二: 无需按顺序 *}
{* 上面的优点三: 路由可以嵌套在一个地方 *}
<Route path="me" element={<OwnUserProfile />} />
<Route path=":id" element={<UserProfile />} />
</Route>
</Routes>
</BrowserRouter>
);
}
function Users() {
return (
<div>
<nav>
{* 上面的优点一: <Link to>是相对的 *}
<Link to="me">My Profile</Link>
</nav>
{* Outlet后面会讲 *}
<Outlet />
</div>
);
}
Обратите внимание на третий пункт выше,К пути вложенного родительского маршрута не нужно добавлять *. Но если он не вложен, а разбросан по подкомпонентам, его нужно добавить в конце*
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
{* 不是嵌套就需要尾部加上* *}
<Route path="users/*" element={<Users />} />
</Routes>
</BrowserRouter>
);
}
function Users() {
return (
<Routes>
<Route element={<UsserLayout />}>
<Route path="me" element={<OwnUserProfile />} />
<Route path=":id" element={<UserProfile />} />
</Route>
</div>
);
}
function UsersLayout() {
return (
<div>
<nav>
<Link to="me">My Profile</Link>
<Link to="2">User Profile</Link>
</nav>
<Outlet />
</div>
);
}
<Route>
<Route element>
Рендеринг или компонент маршрута изменены наelement
<Route path=":userId" element={<Profile animate={true} /> />
function Profile({ animate }) {
const params = useParams();
const location = useLocation();
}
Через эту форму:
- Вы можете передавать реквизиты компонентам, как указано выше.
animate={true}
- Из-за появления хуков больше не нужно передавать некоторые реквизиты маршрута к компоненту через renderProps, мы можем передать
useParams
,useLocation
получить эту информацию
Конечно, есть еще одна важная причина, потому чтоv6
Дети маршрута используются для вложенных маршрутов, как показано ниже.
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="users" element={<Users />}>
<Route path="me" element={<OwnUserProfile />} />
<Route path=":id" element={<UserProfile />} />
</Route>
</Routes>
</BrowserRouter>
);
}
тогда мы собираемся показатьOwnUserProfile
компоненты проходят/users/me
Его можно найти, что кажется довольно интуитивным
<Route path>
v6
имитироватьpath
формате поддерживаются только два динамических заполнителя:
-
:id
параметр стиля -
*
Подстановочные знаки, которые можно использовать только в конце пути, напримерusers/*
дать 🌰
Верны следующие пути:
path = '/groups'
path = '/groups/admin'
path = '/users/:id'
path = '/users/:id/messages'
path = '/files/*' // 通配符放在末尾
path = '/files/:id/*'
path = '/files-*'
Следующий путь неверный:
path = '/users/:id?' // ? 不满足上面两种格式
path = '/tweets/:id(\d+)' // 有正则,不满足上面两种格式
path = '/files/*/cat.jpg'// 通配符不能放中间
<Route caseSensitive>
caseSensitive: boolean
, включать ли режим игнорирования при сопоставлении пути, то есть игнорировать ли регистр при сопоставлении
часть исходного кода
// 根据path生成是regexpSource是否要ignore
const matcher = new RegExp(regexpSource, caseSensitive ? undefined : "i");
<Route index>
index
Означает, является ли маршрут основным. Если установлено значение true, у него не может быть дочерних элементов, как показано ниже.<Route index element={<Home />} />
function App() {
return (
<Routes>
<Route path='/' element={<Layout />}>
<Route path='auth/*' element={<Auth/> } />
<Route path='basic/*' element={<Basic/> } />
</Route>
</Routes>
)
}
function Home() {
return (
<h2> Home </h2>
)
}
function Basic() {
return (
<div>
<h1>Welcome to the app!</h1>
<h2>下面()中的就是真实的Link组件</h2>
<Routes>
<Route element={<Layout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />}/>
...
</Route>
</Routes>
</div>
);
}
Так/basic
автоматически покажет<Home />
и
Макет используется во многих приведенных выше примерах, какая от этого польза? а такжеOutlet
Что это значит?
Давайте посмотрим на код (он лучше работает с картинкой ниже)
function App() {
return (
<Routes>
<Route path='/' element={<Layout />}>
<Route path='auth/*' element={<Auth/> } />
<Route path='basic/*' element={<Basic/> } />
</Route>
</Routes>
)
}
// 下图的最外面的红色框
function Layout() {
return (
<>
<p>主页面</p>
<ul>
<li>
<Link to='auth'>auth</Link>
</li>
<li>
<Link to='basic'>basic</Link>
</li>
</ul>
<hr />
{* 下图蓝色框 *}
<Outlet />
</>
)
}
function Basic() {
return (
<div>
<h1>Welcome to the app!</h1>
<h2>下面()中的就是真实的Link组件</h2>
<Routes>
<Route element={<BasicLayout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />}/>
...
</Route>
</Routes>
</div>
);
}
// 下图绿色框
function BasicLayout() {
return (
<div>
<ul>
...
<Link to=".">Home({` <Link to=".">`})</Link>
...
</li>
</ul>
<Outlet />
</div>
);
}
// 下图黄色框
function Home() {
return (
<h2>Home</h2>
)
}
Из кода и схемы выше мы можем знать, что компонент<Layout/>
Обычно используется как элемент родительского маршрута, в дополнение к рендерингу общедоступного пользовательского интерфейса также есть элементы для рендеринга подмаршрутов.<Outlet/>
, а в коде<Outlet/>
отображается<Basic/>
,<Basic>
из<BasicLayout />
Существуют<Outlet/>
, но он отображает<Route element={<BasicLayout />}>
Элемент, соответствующий маршруту.
Из вышеизложенного мы можем сделать вывод, что:компоненты<Layout/>
Обычно используется как элемент родительского маршрута, в дополнение к рендерингу некоторых общедоступных интерфейсов, среди них<Outlet/>
Функция аналогична слоту, который используется для сопоставления элемента подмаршрута.
useRoutes
Выше мы все используем Route как потомков Routes
function App() {
return (
<Routes>
<Route path='/' element={<Layout />}>
<Route path='auth/*' element={<Auth/> } />
<Route path='basic/*' element={<Basic/> } />
</Route>
</Routes>
)
}
Но мы также можемuseRoutes
Создайте соответствующий элемент
import { useRoutes } from 'react-router-dom'
function App() {
const element = useRoutes([
{
path: '/',
element: <Layout />,
children: [
{
path: 'auth/*',
element: <Auth/>
},
{
path: 'basic/*',
element: <Basic/>
}
]
}
])
return (
{element}
)
}
Этот элемент конфигурации позволяет нам более четко увидеть вложенную структуру маршрута.
<Link>
<Link to>
существуетv5
, еслиto
Не/
Это немного запутано начать с тем, что это зависит от текущего URL. Например, текущий URL/user
, Так<Link to="me">
будет отображаться как<a href="/me">
; и если это/users/
, то он будет отображаться как<a href="/users/me">
.
Затем вv6
решает загадочное явление выше.
существуетv6
, является ли текущий URL/user
еще/users/
,<Link to="me">
будет отображаться как<a href='/user/me'>
.
то естьto
больше похоже на наше обычноеcd
Командная строка, давайте посмотрим больше примеров
<Route path="app">
<Route path="dashboard">
<Route path="stats" />
</Route>
</Route>
// 当前 URL 为 /app/dashboard 或 /app/dashboard/
<Link to="stats"> => <a href="/app/dashboard/stats">
<Link to="../stats"> => <a href="/app/stats">
<Link to="../../stats"> => <a href="/stats">
<Link to="../../../stats"> => <a href="/stats">
// 命令行中, 当前目录为 /app/dashboard
cd stats # pwd is /app/dashboard/stats
cd ../stats # pwd is /app/stats
cd ../../stats # pwd is /stats
cd ../../../stats # pwd is /stats
Важно отметить, что когда<Route path>
При сопоставлении нескольких фрагментов URL<Link to="..">
не всегда отображается как<a href="..">
, в этом случаеto='..'
это путь, основанный на родительском маршруте, пример выглядит следующим образом
function App() {
return (
<Routes>
<Route path="users">
<Route
path=":id/messages"
element={
// 最终是/users, 而不是/:id
<Link to=".." />
}
/>
</Route>
</Routes>
);
}
Если вы этого еще не поняли, мы можем привести крайний пример, например, путь маршрутаbasic/*
, текущий URL-адрес/basic/auth/home
, следующий код
function App() {
return (
<Routes>
<Route path="/">
<Route path="auth/*" element={<Auth />} />
<Route
path="basic/*"
element={
...
<Link to="../auth" />
...
}
/>
</Route>
</Routes>
);
тогда вышеto="../auth"
это прыгнуть к/basic/auth
еще/auth
(ответ/auth
)? Так что во избежание*
Подстановочные знаки могут соответствовать нескольким путям, унифицированным какto='..'
это путь, основанный на родительском маршруте
<Link state>
То есть после нажатия можно датьto
пройти соответствующийstate
<Link replace>
replace:boolean
, по умолчанию false, то есть используется маршрут переходаpush
ещеreplace
<Link target>
тип цели
type HTMLAttributeAnchorTarget =
| '_self'
| '_blank'
| '_parent'
| '_top'
| (string & {});
На самом деле мы этим почти не пользуемся, здесь мы лишь кратко представим значения, которые можно передавать.
useHistory удален и заменен на useNavigate.
Способ применения следующий:
// v6
import { useNavigate } from "react-router-dom";
function App() {
const navigate = useNavigate();
function handleClick() {
navigate("/home");
}
return (
<div>
<button onClick={handleClick}>go home</button>
</div>
);
}
перейти(к) по умолчанию на history.push
// v6
navigate('/home');
//v5
history.push('/home')
перейти (к, { заменить: правда }) is history.replace
// v6
navigate('/home', { replace: true });
//v5
history.replace('/home')
перейти (к: номеру) is history.go
// v6
import { useNavigate } from "react-router-dom";
function App() {
const navigate = useNavigate();
return (
<>
<button onClick={() => navigate(-2)}>
Go 2 pages back
</button>
<button onClick={() => navigate(-1)}>Go back</button>
<button onClick={() => navigate(1)}>
Go forward
</button>
<button onClick={() => navigate(2)}>
Go 2 pages forward
</button>
</>
);
}
// v5
import { useHistory } from "react-router-dom";
function App() {
const { go, goBack, goForward } = useHistory();
return (
<>
<button onClick={() => go(-2)}>
Go 2 pages back
</button>
<button onClick={goBack}>Go back</button>
<button onClick={goForward}>Go forward</button>
<button onClick={() => go(2)}>
Go 2 pages forward
</button>
</>
);
}
naviagete такой же, как , входные параметры аналогичны командной строке cd
<Route path="app">
<Route path="dashboard">
<Route path="stats" />
</Route>
</Route>
// 当前 URL 为 /app/dashboard 或 /app/dashboard/
<Link to="stats"> => <a href="/app/dashboard/stats">
<Link to="../stats"> => <a href="/app/stats">
<Link to="../../stats"> => <a href="/stats">
<Link to="../../../stats"> => <a href="/stats">
// 当前 URL 为 /app/dashboard 或 /app/dashboard/
const navigate = useNavigate()
navigate('stats') => '/app/dashboard/stats'
navigate('../stats') => '/app/stats'
navigate('../../stats') => '/stats'
navigate('../../../stats') => '/stats'
// 命令行中, 当前目录为 /app/dashboard
cd stats # pwd is /app/dashboard/stats
cd ../stats # pwd is /app/stats
cd ../../stats # pwd is /stats
cd ../../../stats # pwd is /stats
Эпилог
Ну, это почти здесь, давайте подытожим некоторые изменения:
-
<Switch>
изменить все на<Routes>
-
Route
изrender
а такжеcomponent
изменить наelement
, и может вкладывать маршруты -
Route
Вы также можете сгенерировать соответствующий элемент, передав вложенный массив в useRoutes. -
to
,navigate
,path
Не/
являются относительными путями в начале, сcd
командная строка как -
<Outlet />
это слот, который может отображать совпадающие подмаршруты
Если вы хотите узнать больше примеров, вы можете открытьreact-router-source-analysis, с большим количеством примеров.
Пока это должно быть, наверное, может анализ исходного кода последнего React-Router в Китае.Если интересно, можете глянуть.Если считаете, что можете, не поскупитесь на свой ⭐
наконец
надо написать позжеReact-Router
Последняя статья по анализу исходного кода, если не ошибаюсь 🐶🐶, ха-ха.
Спасибо, что оставили свои следы.Если вы считаете, что статья хорошая😄😄, пошевелите пожалуйста пальчиками😋😋, лайк + в избранное + вперед🌹🌹