掘金地址:https://juejin.cn/post/7053031843376922660
如需轉(zhuǎn)載,請注明出處
簡介
React Router庫包含三個(gè)不同的npm包,以下每個(gè)包都有不同的用途。
- react-router :核心庫,包含 React Router 的大部分核心功能,包括路由匹配算法和大部分核心組件和鉤子。
- react-router-dom:React應(yīng)用中用于路由的軟件包,包括react-router的所有內(nèi)容,并添加了一些特定于 DOM 的 API,包括BrowserRouter、HashRouter和Link。
- react-router-native: 用于開發(fā)React Native應(yīng)用,包括react-router的所有內(nèi)容,并添加了一些特定于 React Native 的 API,包括NativeRouter和Link。
版本
以下v5從5.1.2所有版本都列出了。v6的還有很多alpha和beta小版本沒有列出。
新項(xiàng)目目前用了6.0.2,之前舊項(xiàng)目用的是5.1.2。
react-router-dom npm地址
| 版本 | 下載量 | 發(fā)布時(shí)間(對比日期2022.1.14) |
|---|---|---|
| 6.2.1 | 818,595 | 1個(gè)月前 |
| 6.0.2 | 464,961 | 2個(gè)月前 |
| 6.0.0 | 5,540 | 2個(gè)月前 |
| 5.3.0 | 1,612,985 | 4個(gè)月前 |
| 5.2.1 | 68,038 | 5個(gè)月前 |
| 6.0.0-beta.0 | 62,966 | 2年前 |
| 5.2.0 | 1,734,184 | 2年前 |
| 6.0.0-alpha.0 | 7 | 2年前 |
| 5.1.2 | 462,691 | 2年前 |
相比v5,打包后的包大小,從20.8k 減少到 10.8k。包分析網(wǎng)站


安裝
// npm 安裝
npm install react-router-dom@6
// yarn 安裝
yarn add react-router-dom@6
啟用全局路由模式
全局路由有常用兩種路由模式可選:HashRouter 和 BrowserRouter 分別是hash模式和history模式。
采用BrowserRouter:
import * as React from "react";
import * as ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
App.jsx 設(shè)置路由
import './App.css';
import { Routes, Route, Link } from "react-router-dom"
function App() {
return (
<div className="App">
<header className="App-header">
<Routes>
<Route path="/" element={<Home />}></Route>
<Route path="/about" element={<About />}></Route>
</Routes>
</header>
</div>
);
}
function Home() {
return <div>
<main>
<h2>Welcome to the homepage</h2>
</main>
<nav>
<Link to="/about">about</Link>
</nav>
</div>
}
function About() {
return <div>
<main>
<h2>Welcome to the about page</h2>
</main>
<nav>
<ol>
<Link to="/">home</Link>
<Link to="/about">about</Link>
</ol>
</nav>
</div>
}
export default App;
寫在前面
如果您剛剛開始使用 React Router,或者您想在新應(yīng)用中試用 v6,請參閱入門指南。
以下內(nèi)容主要敘述的是與React Router v5版本對比的新特性及如何進(jìn)行快速遷移。
升級前準(zhǔn)備
1. 升級到React v16.8
React Router v6 大量使用React hooks,因此在嘗試升級到 React Router v6 之前,您需要使用 React 16.8 或更高版本。好消息是 React Router v5 與 React >= 15 兼容,因此如果您使用的是 v5(或 v4),您應(yīng)該能夠在不接觸任何路由器代碼的情況下升級 React。
2. 升級到React Router v5.1(非必要)
如果您先升級到 v5.1,則切換到 React Router v6 會更容易。因?yàn)樵?v5.1 中,發(fā)布了對元素處理的增強(qiáng),<Route children>這將有助于平滑過渡到 v6。不要使用<Route component>和<Route render>props,而是在任何地方使用常規(guī)元素<Route children>并使用鉤子來訪問路由器的內(nèi)部狀態(tài)。
升級到 React Router v6
- <Switch>重命名為<Routes>。
- <Route>的新特性變更。
- 嵌套路由變得更簡單。
- 用useNavigate代替useHistory。
- 新鉤子useRoutes代替react-router-config。
1. <Switch>重命名為<Routes>
React Router v6 引入了一個(gè)Routes的組件,類似于以前的Switch,但功能更強(qiáng)大。它包括相對路由和鏈接、自動(dòng)路由排名、嵌套路由和布局等功能。
// v5
<Switch>
<Route exact path="/"><Home /></Route>
<Route path="/profile"><Profile /></Route>
</Switch>
// v6
<Routes>
<Route path="/" element={<Home />} />
<Route path="profile/*" element={<Profile />} />
</Routes>
2.<Route>的新特性變更
Route負(fù)責(zé)渲染React組件的UI。在v6中會用到兩個(gè)屬性:
- path:與當(dāng)前頁面對應(yīng)的URL匹配。
- element:這個(gè)是新增的,用于決定路由匹配時(shí),渲染哪個(gè)組件。在v5的時(shí)候,我們通常會用到component這個(gè)屬性,或者是render。
簡單來說,component/render被element替代
// v5
<Route path=":userId" component={Profile} />
<Route
path=":userId"
render={routeProps => (
<Profile routeProps={routeProps} animate={true} />
)}
/>
// v6
<Route path=":userId" element={<Profile />} />
<Route path=":userId" element={<Profile animate={true} />} />
3. 嵌套路由更簡單
嵌套路由在實(shí)際應(yīng)用中很常見,如以下兩個(gè)頁面,User這個(gè)組件是共用的,切換路由的時(shí)候,僅改變Profile和Posts子組件。

在React Router v5中,必須明確定義嵌套路由,React Router v6并非如此。它從React Router庫中挑選了一個(gè)名為 Outlet 的最佳元素,為特定路由呈現(xiàn)任何匹配的子元素。用起來和Vue Router里的<router-view>差不多。
3.1 Outlet實(shí)現(xiàn)嵌套路由
- v5中實(shí)現(xiàn)嵌套路由
// v5
import {
BrowserRouter,
Switch,
Route,
Link,
useRouteMatch
} from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/profile" component={Profile} />
</Switch>
</BrowserRouter>
);
}
function Profile() {
let { path, url } = useRouteMatch();
return (
<div>
<nav>
<Link to={`${url}/me`}>My Profile</Link>
</nav>
<Switch>
<Route path={`${path}/me`}>
<MyProfile />
</Route>
<Route path={`${path}/:id`}>
<OthersProfile />
</Route>
</Switch>
</div>
);
}
- v6中實(shí)現(xiàn)嵌套路由,可以刪除字符串匹配邏輯。不需要任何useRouteMatch()。利用新API:Outlet( 利用下面第5點(diǎn)說到的useRoutes,可以進(jìn)一步簡化。 )
import { Outlet } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="profile" element={<Profile />}>
<Route path=":id" element={<MyProfile />} />
<Route path="me" element={<OthersProfile />} />
</Route>
</Routes>
</BrowserRouter>
);
}
function Profile() {
return (
<div>
<nav>
<Link to="me">My Profile</Link>
</nav>
{/*將直接根據(jù)上面定義的不同路由參數(shù),渲染<MyProfile />或<OthersProfile /> */}
<Outlet />
</div>
)
}
3.2 多個(gè)<Routes />
以前,我們只能 在React App中使用一個(gè) Routes。但是現(xiàn)在我們可以在React App中使用多個(gè)路由,這將幫助我們基于不同的路由管理多個(gè)應(yīng)用程序邏輯。
import React from 'react';
import { Routes, Route } from 'react-router-dom';
function Dashboard() {
return (
<div>
<p>Look, more routes!</p>
<Routes>
<Route path="/" element={<DashboardGraphs />} />
<Route path="invoices" element={<InvoiceList />} />
</Routes>
</div>
);
}
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="dashboard/*" element={<Dashboard />} />
</Routes>
);
}
4. 用useNavigate代替useHistory
從一目了然改到雙目失明。。。
// v5
import { useHistory } from 'react-router-dom';
function MyButton() {
let history = useHistory();
function handleClick() {
history.push('/home');
};
return <button onClick={handleClick}>Submit</button>;
};
現(xiàn)在,history.push()將替換為navigation()
// v6
import { useNavigate } from 'react-router-dom';
function MyButton() {
let navigate = useNavigate();
function handleClick() {
navigate('/home');
};
return <button onClick={handleClick}>Submit</button>;
};
history的用法也將被替換成:
// v5
history.push('/home');
history.replace('/home');
// v6
navigate('/home');
navigate('/home', {replace: true});
5. 用新鉤子useRoutes代替react-router-config
這個(gè)hooks用完,比上面直接寫router組件的jsx文件要簡潔很多
function App() {
let element = useRoutes([
{ path: '/', element: <Home /> },
{ path: 'dashboard', element: <Dashboard /> },
{ path: 'invoices',
element: <Invoices />,
children: [
{ path: ':id', element: <Invoice /> },
{ path: 'sent', element: <SentInvoices /> }
]
},
// 404找不到
{ path: '*', element: <NotFound /> }
]);
return element;
}
項(xiàng)目實(shí)踐
以下例子都基于useRoutes
tips:例子中fullPath這個(gè)屬性是自己定義的非官方屬性,因?yàn)榍短茁酚傻臅r(shí)候,path只需要寫相對的路徑。為了方便直接看到包含父路徑的完整路徑,所以定義這個(gè)用于查看,實(shí)際React Router并不會用到這個(gè)屬性。
1. 懶加載
import { useRoutes } from 'react-router-dom'
// 懶加載
const lazyLoad = (path: string) => {
const Comp = React.lazy(() => import(`@page/${path}`))
return (
<React.Suspense fallback={<>加載中...</>}>
<Comp />
</React.Suspense>
)
}
const routers = [
{
name: '項(xiàng)目',
path: '/',
element: <Backbone />,
children: [
{
name: '首頁',
path: 'index/*',
// 這個(gè)屬性實(shí)際路由渲染不會用到。
fullPath: '/index',
element: lazyLoad('IndexPage')
}
]
]
const Index = () => useRoutes(routers)
export default Index
2. Index路由:默認(rèn)子路由
用于嵌套路由,僅匹配父路徑時(shí),設(shè)置渲染的組件。 解決當(dāng)嵌套路由有多個(gè)子路由但本身無法確認(rèn)默認(rèn)渲染哪個(gè)子路由的時(shí)候,可以增加index屬性來指定默認(rèn)路由。
index路由和其他路由不同的地方是它沒有path屬性,他和父路由共享同一個(gè)路徑。
例如: 以下路由設(shè)置了兩個(gè)子路由,分別是/foo/invoices 和 /foo/activity 。但是當(dāng)頁面直接訪問 /foo的時(shí)候,頁面就不知道怎么渲染了。這時(shí)候可以通過index設(shè)置默認(rèn)展示到invoices。
const routers = [
{
name: '項(xiàng)目',
path: '/foo',
element: <Layout />,
children: [
// 僅匹配到父級路由時(shí), 設(shè)置index為true,不需要指定path
{ index: true, element: lazyLoad('Invoices') },
{
name: '首頁',
path: 'invoices',
element: lazyLoad('Invoices')
},
{
name: 'about',
path: 'activity',
element: lazyLoad('Activity')
}
]
}
]
3. 404
廢棄了V5中的Redirect
// v5 廢棄了
const routers = [
{ path: 'home', redirectTo: '/' }
]
// 404可以這么寫
const routers = [
{
name: '404',
path: '*',
element: <NoMatch />
}
]
4. 動(dòng)態(tài)路由
我們經(jīng)常需要把某種模式匹配到的所有路由,全都映射到同個(gè)組件。例如新聞詳情頁,對應(yīng)不同新聞,都對應(yīng)到News組件,路徑可能為 news/1,news/2...。其中數(shù)字1為新聞的id。這個(gè)是動(dòng)態(tài)變化。
- 動(dòng)態(tài)路徑參數(shù) 以冒號開頭
const routers = [
{
name: '公告詳情頁',
// 動(dòng)態(tài)路徑參數(shù) 以冒號開頭
path: 'noticeDetail/:id',
fullPath: '/noticeDetail',
element: lazyLoad('NoticeDetail')
},
{
name: '幫助中心詳情頁',
path: 'helpCenterDetail/:fid/:sid',
fullPath: '/helpCenterDetail',
element: lazyLoad('HelpCenterDetail')
}
]
-
useParams 用于組件獲取動(dòng)態(tài)路徑的參數(shù)
例如上面這個(gè)例子,有兩個(gè)動(dòng)態(tài)參數(shù)fid和sid,在HelpCenterDetail組件:
import { useParams } from 'react-router-dom'
const { fid, sid } = useParams()
5. 路由通配符
支持以下幾種通配符號。注意:這里的*只能用在/后面,不能用在實(shí)際路徑中間
/groups
/groups/admin
/users/:id
/users/:id/messages
/files/*
/files/:id/*
以下這些v6里面不支持
/users/:id?
/tweets/:id(\d+)
/files/*/cat.jpg
/files-*
6. url搜索參數(shù)
useSearchParams的使用。
例如 :http://URL/user?id=111,獲取id對應(yīng)的值
import { useSearchParams } from 'react-router-dom'
const [searchParams, setSearchParams] = useSearchParams()
// 獲取參數(shù)
searchParams.get('id')
// 判斷參數(shù)是否存在
searchParams.has('id')
// 同時(shí)頁面內(nèi)也可以用set方法來改變路由
setSearchParams({"id":2})
7. withRouter
v6不再提供withRouter,略坑。
官方解釋:這個(gè)問題通常源于您使用的是不支持鉤子的 React 類組件。在 React Router v6 中,我們完全接受了鉤子并使用它們來共享所有路由器的內(nèi)部狀態(tài)。但這并不意味著您不能使用路由器。假設(shè)您實(shí)際上可以使用鉤子(您使用的是 React 16.8+),您只需要一個(gè)包裝器。
import {
useLocation,
useNavigate,
useParams
} from "react-router-dom";
function withRouter(Component) {
function ComponentWithRouterProp(props) {
let location = useLocation();
let navigate = useNavigate();
let params = useParams();
return (
<Component
{...props}
router={{ location, navigate, params }}
/>
);
}
return ComponentWithRouterProp;
}
項(xiàng)目中完整例子
import { useRoutes } from 'react-router-dom'
import Backbone from '../layouts/Backbone'
import InfoPage from '../pages/InfoPage/index'
import DataCenterPage from '../pages/DataCenterPage/index'
import NoMatch from './NoMatch'
// 懶加載
const lazyLoad = (path: string) => {
const Comp = React.lazy(() => import(`@page/${path}`))
return (
<React.Suspense fallback={<>加載中...</>}>
<Comp />
</React.Suspense>
)
}
const routers = [
{
name: '項(xiàng)目',
path: '/',
element: <Backbone />,
children: [
// 僅匹配到父級路由時(shí)
{ index: true, fullPath: '/', element: lazyLoad('IndexPage') },
{
name: '首頁',
path: 'index/*',
fullPath: '/index',
element: lazyLoad('IndexPage')
},
{
name: '消息中心',
path: 'info/',
// element: lazyLoad('InfoPage'),
element: <InfoPage />,
children: [
{ index: true, fullPath: '/info', element: lazyLoad('NoticeList') },
{
name: '公告',
path: 'noticeList',
fullPath: '/info/noticeList',
element: lazyLoad('NoticeList')
},
{
name: '幫助中心',
path: 'helpCenter',
fullPath: '/info/helpCenter',
element: lazyLoad('HelpCenter')
}
]
},
{
name: '我要推廣',
path: 'activityList/*',
fullPath: '/activityList',
element: lazyLoad('ActivityList')
},
{
name: '數(shù)據(jù)中心',
path: 'data/',
// element: lazyLoad('InfoPage'),
element: <DataCenterPage />,
children: [
{ index: true, fullPath: '/data', element: lazyLoad('Order') },
{
name: '訂單查詢',
path: 'order',
fullPath: '/data/order',
element: lazyLoad('Order')
},
{
name: '收益查詢',
path: 'reward',
fullPath: '/data/reward',
element: lazyLoad('Reward')
},
{
name: '結(jié)算查詢',
path: 'settlement',
fullPath: '/data/settlement',
element: lazyLoad('Settlement')
}
]
}
]
},
{
name: '公告詳情頁',
// 動(dòng)態(tài)路由
path: 'noticeDetail/:id',
fullPath: '/noticeDetail',
element: lazyLoad('NoticeDetail')
},
{
name: '幫助中心詳情頁',
path: 'helpCenterDetail/:fid/:sid',
fullPath: '/helpCenterDetail',
element: lazyLoad('HelpCenterDetail')
},
{
name: '個(gè)人注冊頁',
path: 'register/person',
fullPath: '/register/person',
element: lazyLoad('PersonBaseInfo')
},
{
name: '404',
path: '*',
element: <NoMatch />
}
]
const Index = () => useRoutes(routers)
export default Index
常用路由組件和hooks
完整API: https://reactrouter.com/docs/en/v6/api
| 組件名 | 作用 | 說明 |
|---|---|---|
<Routers> |
一組路由 | 代替原有<Switch>,所有子路由都用基礎(chǔ)的Router children來表示 |
<Router> |
基礎(chǔ)路由 | Router是可以嵌套的,解決原有V5中嚴(yán)格模式 |
<Link> |
導(dǎo)航組件 | 在實(shí)際頁面中跳轉(zhuǎn)使用 |
<Outlet/> |
自適應(yīng)渲染組件 | 根據(jù)實(shí)際路由url自動(dòng)選擇組件,主要用于嵌套路由,類似Vue Router中的<router-view>
|
| hooks名 | 作用 | 說明 |
|---|---|---|
| useParams | 返回當(dāng)前參數(shù) | 根據(jù)路徑讀取參數(shù) |
| useNavigate | 返回當(dāng)前路由 | 代替原有V5中的 useHistory |
| useOutlet | 返回根據(jù)路由生成的element | |
| useLocation | 返回當(dāng)前的location 對象 | |
| useRoutes | 同Routers組件一樣,只不過是在js中使用 | 代替react-router-config |
| useSearchParams | 用來匹配URL中?后面的搜索參數(shù) |
參考文獻(xiàn)
React Router網(wǎng)址: React Router
React Router文檔: https://reactrouter.com/docs/en/v6
完整API: https://reactrouter.com/docs/en/v6/api
react-router-dom: npm地址
參考博客:https://blog.csdn.net/weixin_40906515/article/details/104957712
https://zhuanlan.zhihu.com/p/191419879
http://www.itdecent.cn/p/03234215a90e
https://blog.csdn.net/zjjcchina/article/details/121921585
包大小分析網(wǎng)站: https://bundlephobia.com/