React Router(react-router-dom V6 整理)
阿新 • • 發佈:2022-04-11
官方文件
一個神奇的連結: React Router 官方文件
安裝
執行以下命令安裝React Router:
npm install react-router-dom@6 --save
注意:react-router-dom
包含所有內容,匯入元件時應該從react-router-dom
中匯入,而不應該從 react-router
中匯入,否則,會意外地在應用中匯入不匹配的庫版本;
基本用法
在Web應用程式中開啟 React Router 功能
// index.js import React from 'react'; import { createRoot } from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; import App from './App'; const container = document.getElementById('root'); const root = createRoot(container); root.render( // 通過在應用入口新增 BrowserRouter 元件開啟 React Router 功能 <BrowserRouter> <React.StrictMode> <App /> </React.StrictMode> </BrowserRouter> );
注意:web 應用程式中一般使用 BrowserRouter
元件, 還用另一種 HashRouter
元件方式;
這兩種方式的區別:
- 底層原理不一樣:
BrowserRouter
呼叫的是H5 history API,低版本相容性問題。HashRouter
使用的是URL雜湊值 - 位址列表現形式不一樣:
BrowserRouter
的路徑:localhost:3000/indexHashRouter
的路徑:localhost:3000/#/index - 重新整理後對路由state引數的影響
BrowserRouter
沒有任何影響,因為state儲存在history物件中HashRouter
重新整理後會導致路由state引數的丟失
值得注意的是,官方強烈建議不要使用 HashRouter
;
配置路由
點選檢視程式碼
// App.js // 匯入 Route, Routes 元件 import { Route, Routes } from 'react-router-dom'; function App() { return ( <Routes> {/* 頁面預設導航到 Home 元件(頁面上顯示 Home Compontent) */} <Route path='/' element={<Home />} /> {/* 在地址輸入 http://localhost:3000/about 導航到 About 元件(頁面上顯示 About Compontent) */} <Route path='/about' element={<About />} /> </Routes> ); } const Home = (props) => { return <div>Home Compontent</div>; } const About = (props) => { return <div>About Compontent</div>; } export default App;
在以前版本的 React Router 中,必須以某種方式對路由進行排序,以便在多個路由與不明確的 URL 匹配時獲得要呈現的正確路由。V6更智慧,將選擇最具體的匹配;
新增 "不匹配" 路由
點選檢視程式碼
// App.js
import { Route, Routes } from 'react-router-dom';
function App() {
return (
<Routes>
<Route path='/' element={<Home />} />
<Route path='/about' element={<About />} />
{/* 當沒有其他路由與 URL 匹配時,匹配 path='*'的路由 */}
<Route path='*' element={<NotFount />} />
</Routes>
);
}
const Home = (props) => {
return <div>Home Compontent</div>;
}
const About = (props) => {
return <div>About Compontent</div>;
}
const NotFount = (props) => {
return <div>NotFount !!!</div>;
}
export default App;
當沒有其他路由與 URL 匹配時,才會匹配 path='*'
路由。此路由將匹配任何 URL,但優先順序最弱,因此路由器僅在沒有其他路由匹配時才會選擇它;
使用連結導航
點選檢視程式碼
// App.js
// 匯入 Link 元件
import { Route, Routes, Link } from 'react-router-dom';
function App() {
return (
<Routes>
{/* 頁面預設導航到 Home 元件(渲染 Home 元件, 頁面顯示 About Compontent 連結) */}
<Route path='/' element={<Home />} />
<Route path='/about' element={<About />} />
</Routes>
);
}
const Home = (props) => {
return <div>
{/* 點選 About Link 連結跳轉至 http://localhost:3000/about
畫面顯示 About 元件內容(Home Link連結)
*/}
<Link to='/about'>About Link</Link>
</div>;
}
const About = (props) => {
return <div>
{/* 點選 Home Link 連結跳轉至 http://localhost:3000/
畫面顯示 Home 元件內容(About Link連結)
*/}
<Link to='/'>Home Link</Link>
</div>;
}
export default App;
使用巢狀路由
點選檢視程式碼
// App.js
// 匯入 Link, Outlet 元件
import { Route, Routes, Link, Outlet } from 'react-router-dom';
function App() {
return (
<Routes>
<Route path='/' element={<Home />} >
<Route path='about' element={<About />} />
<Route path='setting' element={<Setting />} />
{/* 預設子路由
如果導航欄地址為 http://localhost:3000,此時子路由渲染位置(Outlet)為空白,
增加以下配置,子路由渲染位置(Outlet)渲染 <List />
*/}
<Route index element={<List />} />
</Route>
</Routes>
);
}
const Home = (props) => {
return <>
<div>
<Link to='/about'>About Link</Link> | {" "}
<Link to='/setting'>Setting Link</Link>
</div>
<div style={{padding: '20px', margin: '10px', borderTop: '1px solid'}}>
{/* Outlet 為巢狀子路由的出口,比如:點選 About Link 連結,
瀏覽器地址變為 http://localhost:3000/about
在此渲染路由地址為 /about 的元件(在此顯示: About Compontent)
*/}
<Outlet />
</div>
</>;
}
const About = (props) => {
return <div>
About Compontent
</div>;
}
const Setting = (props) => {
return <div>
Setting Compontent
</div>;
}
const List = (props) => {
return <div>
List Compontent
</div>;
}
export default App;
這是 React Router 最強大的功能之一,在實際開發中,大多數 UI 都是一系列巢狀佈局,React Router 通過這種巢狀路由的方式實現了一些自動、持久的佈局處理;
使用活動連結
點選檢視程式碼
// App.js
// 匯入 NavLink 元件
import { Route, Routes, NavLink, Outlet } from 'react-router-dom';
function App() {
return (
<Routes>
<Route path='/' element={<Home />} >
<Route path='about' element={<About />} />
<Route path='setting' element={<Setting />} />
<Route index element={<List />} />
</Route>
</Routes>
);
}
const Home = (props) => {
return <>
<div>
{/* <NavLink /> 接收一個style 或者 className 屬性
屬性值為一個回撥函式,可以通過 isActive 的值判斷
連結是否處於活動狀態,從而實現給活動連結節點新增樣式的效果
示例效果:點選哪個連結,目標連結字型變紅
*/}
<NavLink
style={({ isActive }) => navColor(isActive)}
to='/about'
>
About Link
</NavLink> | {" "}
<NavLink
style={({isActive}) => navColor(isActive)}
to='/setting'
>
Setting Link
</NavLink>
</div>
<div style={{ padding: '20px', margin: '10px', borderTop: '1px solid' }}>
<Outlet />
</div>
</>;
}
const About = (props) => {
return <div>
About Compontent
</div>;
}
const Setting = (props) => {
return <div>
Setting Compontent
</div>;
}
const List = (props) => {
return <div>
List Compontent
</div>;
}
const navColor = (isActive) => {
return {color: isActive ? 'red' : ""}
}
export default App;
讀取 URL 引數
點選檢視程式碼
// 匯入 useParams 元件
import { Route, Routes, NavLink, Outlet, useParams } from 'react-router-dom';
function App() {
return (
<Routes>
<Route path='/' element={<Home />} >
<Route path='list' element={<List />} >
<Route path=':id' element={<Item />} />
</Route>
</Route>
</Routes>
);
}
const Home = (props) => {
return <>
<div>
<NavLink
style={({ isActive }) => navColor(isActive)}
to='/list'
>
List Link
</NavLink>
</div>
<div style={{ padding: '20px', margin: '10px', borderTop: '1px solid' }}>
<Outlet />
</div>
</>;
}
const Item = (props) => {
// 從 URL 獲取引數::id
const params = useParams();
return <h2>Item: {params.id}</h2>;
}
const List = (props) => {
const list = [
{
name: "趙雲",
no: 100
},
{
name: "馬超",
no: 101
}
]
return <div>
{list.map((item) => {
return (<NavLink
style={({isActive}) => navColor(isActive)}
to={`/list/${item.no}`}
key={item.no}
>
{item.name}
</NavLink>)
})}
<div className='content'>
{/* 指定子路由 /list/? 的渲染位置 */}
<Outlet />
</div>
</div>;
}
const navColor = (isActive) => {
return {
color: isActive ? 'red' : "",
marginRight: '10px'
}
}
export default App;
與 V5 的區別
-
<Routes>
替代<Switch>
寫法上的比較:// v5 寫法 // 引入 react-router import { Route, Switch } from 'react-router-dom'; function App() { return ( <Switch> {/* 路由配置 */} </Switch> ); } // v6 寫法 import { Route, Routes } from 'react-router-dom'; function App() { return ( // Routes 替換 Switch <Routes> {/* 路由配置 */} </Routes> ); }
-
<Route>
不再支援子元件,改為使用 element 屬性;並且不再需要 exact 屬性了
寫法上的比較:// v5 寫法 // 引入 react-router import { Route, Switch } from 'react-router-dom'; function App() { return ( <Switch> <Route exact path='/home'> <Home /> </Route> </Switch> ); } // v6 寫法 import { Route, Routes } from 'react-router-dom'; function App() { return ( <Routes> <Route path='/home' element={<Home /> } /> </Routes> ); }
- 移除了
<NavLink>
的 activeClassName 屬性
v6寫法:import { NavLink } from 'react-router-dom'; function App() { return ( <> {/* className 寫法 */} <NavLink className={({isActive}) => { return isActive ? "highlight" : ""; }} to="home">Home</NavLink> {/* style 寫法 */} <NavLink to="about" style={({isActive}) => { return { color: isActive ? "red" : "" } }} >About</NavLink> </> ); }
- 移除
<Redirect>
,改為使用<Navigate>
寫法上的對比:// v6 寫法 import { Navigate, Route, Routes } from 'react-router-dom'; function App() { return ( <Routes> <Route path='/' element={<Navigate replace to="/home" />} /> </Routes> ); }
-
<Link to>
支援相對位置// If your routes look like this <Route path="app"> <Route path="dashboard"> <Route path="stats" /> </Route> </Route> // and the current URL is /app/dashboard (with or without // a trailing slash) <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">
- 新增
<Outlet>
關於<Outlet>
,參考本文的巢狀路由節點; 此元件是一個佔位符,告訴 React Router 巢狀的內容應該放到哪裡; 通過<Outlet>
可以將所有的路由(巢狀的子路由)配置合併在一起,可進行路由的統一管理,增加了程式碼可維護性; - 使用 useNavigate 實現程式設計式導航,從而代替 useHistory
// v6 寫法 import { useNavigate } from 'react-router-dom'; function App() { const navigate = useNavigate(); const handleClick = () => { navigate('/home'); // push // 重定向 // navigate('/home', {replace: true}); }; return ( <div> <button onClick={handleClick}>返回首頁</button> </div> ); }
- 一系列的 Hooks
hooks名 作用 說明 useParams
返回當前引數 根據路徑讀取引數 useNavigate
返回當前路由 代替原有V5中的 useHistory useOutlet
返回根據路由生成的element useLocation
返回當前的location 物件 useRoutes
同Routers元件一樣,只不過是在js中使用 useSearchParams
用來匹配URL中?後面的搜尋引數
總結
本文主要記錄了一下 React Router V6 的一些基本用法以及對V5的比較,有了這些知識的支撐,足以應付大多數日常開發了;v6 版本基於全新的路由演算法帶來強大的功能和 hooks,並且重新實現了 useNavigate 來替代 useHistory ,整體上更加好理解;
先記錄這麼多,後續持續更新!!!