最近使用了一下react-router@6
版本感覺有很大的改動,記錄一下。
React Router v6 makes heavy use of React hooks, so you'll need to be on React 16.8 or greater before attempting the upgrade to React Router v6. The good news is that React Router v5 is compatible with React >= 15, so if you're on v5 (or v4) you should be able to upgrade React without touching any of your router code.
官網給出的原文上面說的很清楚了,在 6 版本上使用了React Hooks
寫法,說明不支援class
類來寫。並且要求react
版本在16.8
以上。如果想相容class
元件 以及 react@15
使用只能用react-router@5版本
。
安裝
D:\your_project> npm i react-router-dom@6
# or
D:\your_project> yarn add react-router-dom@6
# or
D:\your_project> cnpm i react-router-dom@6
變化
Switch
與 Routes
在 v5 版本中必須明確的說明巢狀的的路由和連結,那麼就要獲取父路由的屬性等等。在 v6 版本則不需要,因為路徑是相對的
。案例如下:
// react-router-dom v5.1
import {
BrowserRouter,
Switch,
Route,
Link,
useRouteMatch,
} from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" children={<Home />} />
<Route path="/users" children={<Users />} />
</Switch>
</BrowserRouter>
);
}
function Users() {
// 獲取當前 router 匹配資訊 { path:string , url: string , }
const match = useRouteMatch();
return (
<div>
<div className="link">
<Link to={`${match.url}/me`}>My Profile</Link>
</div>
<Switch>
{/* path = /users/me */}
<Route path={`${match.path}/me`}>
<OwnUserProfile />
</Route>
{/* path = /users/:id */}
<Route path={`${match.path}/:id`}>
<UserProfile />
</Route>
</Switch>
</div>
);
}
在 v6 版本後 再父元件裡寫的路徑若無 /
開頭 都是相對父元件。案例如下:
// react-router-dom v6+
import {
BrowserRouter,
Routes,
Route,
Link,
} from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
{/* /users 下的所有路徑 渲染 User元件 /user /user/* */}
<Route path="/users/*" element={<Users />} />
</Routes>
</BrowserRouter>
);
}
function Users() {
return (
<div>
<nav>
{ /* to = /users/me */ }
<Link to="me">My Profile</Link>
</nav>
{/* 子元件 path 直接相對父元件 */}
<Routes>
{/* /user/me */}
<Route path="me" element={<OwnUserProfile />} />
{/* /user/:id */}
<Route path=":id" element={<UserProfile />} />
</Routes>
</div>
);
Route
- Route Props.path
是相對的,它們會自動在父路由的路徑和 URL 上構建。
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="users" element={<Users />}>
{/* /user/me */}
<Route path="me" element={<OwnUserProfile />} />
{/* /user/:id */}
<Route path=":id" element={<UserProfile />} />
</Route>
</Routes>
</BrowserRouter>
- Route (Props.
component
| Props.render
| Props.children
)廢棄
-> 使用 Props.element
在 v5 版本 路由可以使用 三種屬性來掛載元件,但是在 v6 版本 只有一種 就是 element
屬性。
// react-router-dom v5.x
function Page() {
return <div> page 元件 </div>;
}
// 使用 component 掛載元件
<Route path="/page" component={Page} />;
// 使用 render 掛載元件
<Route
path="/page"
render={(routerProps) => <Page routerProps={routerProps} />}
/>;
// 使用 children 掛載元件
<Route path="/page" children={<Page />} />;
<Route path="/page">
<Page />
</Route>;
Redirect (移除)
在 v5 版本中 <Switch>
裡 使用 <Redirect>
元件進行路由重定向。
// v5.x
// any code ...
<Switch>
<Route path="/user" children={<User />} />
</Switch>;
function User({ userInfo }) {
if (!userInfo) {
// 重定向 到 登入頁
return <Redirect to="/login" />;
}
return <div>User Page</div>;
}
在 v6 版本中 將使用 Navigation
// v6.x
// any code ...
<Switch>
<Route path="/user" children={<User />} />
</Switch>;
function User({ userInfo }) {
if (!userInfo) {
// 重定向 到 登入頁
return <Navigation to="/login" />;
}
return <div>User Page</div>;
}
Switch (移除)
在 v5 版本中 用 <Switch>
元件包裹 <Route>
路由元件, 現在改用 <Routes>
// v5.x
<Switch>
<Route path="/" children={<Home />} />
<Route path="/user" children={<User />} />
</Switch>
// v6.x
<Routes>
<Route path="/" element={<Home />} />
<Route path="/user" element={<User />} />
</Routes>
Link
Link 元件主要用於路由跳轉,在 v5 版本 Link
的 to
屬性是根據當前 url
。舉例:
// 當前 路由路徑 /user
<Link to="me" /> // render <a href="/me" >...</a>
// 當前 路由路徑 /user/
<Link to="me" /> // render <a href="/user/me" >...</a>
而在 v6 版本中 如果Link
在 Route
裡渲染 to
屬性是根據當前<Route>
路由的匹配的 url
;如果不在Route
元件裡掛載的,則是根據 BrowserRouter.basename
渲染 跳轉路徑,預設/
。
// v6.x
import { BrowserRouter, Link, Outlet, Route, Routes } from "react-router-dom";
<BrowserRouter>
<Link to=""> go Home</Link> | <Link to="user"> go user</Link>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/user" element={<User />}>
<Route path=":id" element={<Person />} />
</Route>
</Routes>
</BrowserRouter>;
function Home() {
return (
<div>
<h1>Home page</h1>
</div>
);
}
function User() {
return (
<div>
<h1>User page</h1>
<Link to="..">go Home</Link>
<Link to="abc">go User abc</Link>
<hr />
<Outlet />
</div>
);
}
function Person() {
return (
<div>
<h1>User abc page</h1>
<Link to="..">go user</Link>
<Link to="../..">go Home</Link>
</div>
);
}
如果你把 url 看作檔案路徑,你發現 Link
的 to
相當於 cd
跳轉。
<Route path="app">
<Route path="dashboard">
<Route path="stats" />
</Route>
</Route>
<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
NavLink
Props.exact
命名為 Props.end
,刪除Props.activeClassName
,Props.activeStyle
使用函式返回style,className
。
// v5.x
const style = { color : "red" }
<NavLink to="/user" exact />
<NavLink to="/user" activeClassName="active-link" />
<NavLink to="/user" activeStyle={style} />
// v6.x
const getCls = ({ isActive }) => isActive ? "link" : "ative link";
const getStyle = ({ isActive }) => ({ color: isActive ?'red': 'blue' })
<NavLink to="/user" end /> // 精確匹配
<NavLink to="/user" className={getCls} />
<NavLink to="/user" activeStyle={getStyle} />
useRouteMatch (替換) useMatch
新增
Navigate 跳轉路由元件
<Navigate>
元件和 useNavigate
hooks api 擁有一樣的用法。在函式元件使用 useNavigate
api,而在 class 元件,可以使用 Navigate
元件進行掛載跳轉路由。
interface NavigateProps {
to: To;
replace?: boolean;
state?: any;
}
class User extends React.Component {
render() {
const { userInfo } = this.props;
if (!userInfo) {
return <Navigate to="/login" replace />;
}
return <div>User</div>;
}
}
Outlet 路由檢視元件
當 Route
下有子 Route
的時候 需要使用 Outlet
顯示子路由內容。
useLocation hooks
獲取當前路由位置
物件。如果您想在當前位置更改時執行一些副作用,這可能很有用。
import { useEffect } from "react"
import { useLocation } from 'react-router-dom';
function App() {
let location = useLocation();
useEffect(() => {
// do something
}, [location]);
return (
// ...
);
}
useNavigate hooks
呼叫返回一個函式,該函式呼叫第一個引數為string
型別 與 <Link>
to
屬性 效果一樣,為number
型別,在歷史記錄堆疊中傳遞要訪問的增量。第二個引數 與 <Link>
的 state,replace
型別相同。 替代了 v5 版本中的 history
物件
import { useNavigate } from "react-router-dom";
function App(){
const navigate = useNavigate();
const submit = (data)=>{
api(data).then(res=>{
navigate("/user")
})
}
const back = ()=>{
navigate(-1) // 後退一頁
}
return (
// ...
)
}
useParams hooks
獲取路由:
匹配的資訊,返回當前 URL 中與 匹配的動態引數的鍵/值對的物件。
import { useParams } from "react-router-dom";
function Person(){
const { id } = useParams() // path = /user/:id => current url = /user/1
console.log(id) // 1
return (
// ....
)
}
useRoutes hooks
使用陣列來定義路由。返回路由元件。
import { useRoutes } from "react-router-dom";
const routes = [
{
path: "/",
element: <Home />,
children: [
{
path: "/test",
element: <Test />,
},
],
},
{
path: "*",
element: <NotFound />,
},
];
function App() {
const router = useRoutes(routes);
return router;
}
useSearchParams hooks
用於讀取和設定 url 的query
部分,返回和 react useState hooks 一樣。每次searchParams
修改相當於路由 push 一次。
import { useSearchParams } from "react-router-dom";
// current url => /
function App() {
const [searchParams, setSearchParams] = useSearchParams();
const setQueryId = () => {
// url change => /?id=2&name=test
setSearchParams({
id: 2,
name: "test",
});
};
return (
<div>
<h1> current query id :{searchParams.get("id")}</h1>
<button onClick={setQueryId}>set id</button>
</div>
);
}
-
searchParams
-
searchParams.get(str) 返回 string | null
獲取 url 的 query 第一個匹配上的的
str
值.例如/user?id=1
=> searchParams.getAll('id') 返回值為為'1'
-
searchParams.getAll(str) 返回 string[]
獲取 url 的 query 所有的
str
值.例如/user?id=1&id=2
=> searchParams.getAll('id') 返回值為['1','2']
-
-
setSearchParams
修改當前 url query 部分。相當於路由跳轉了。你可以使用第二個引數,進行是否推入
history
棧。例如:setSearchParams({ id : 2 },{ replace : true })
相當於history.replace({currentUrl}/?id=2)