React Router6學習
第1節和第2節是課程中的MD筆記, 第3節是在聽課過程中自己記的筆記和從網上查的總結, 細節更多.
1. 概述
1.1 React Router以三個不同的包發布到npm上,他們分別是
- react-router:路由的核心庫, 提供了很多的:組件、鈎子。
- react-router-dom:包含react-router所有內容,並添加了一些專門用於DOM的組件,例如
<BrowserRouter>
等。 - react-router-native: 包括react-router所有內容,並添加一些專門用於ReactNative的API,例如:
<NativeRouter>
等。
1.2 與React Router 5.x 版本相比,改變了什么?
- 內置組件的變化:移除了
<Switch>
,新增了<Routes/>
等。 - 語法的變化:
component={About}
變為了element={About}
等。 - 新增多個hook:
useParams
useNavigate
useMatch
等。 - 官方明確推薦函數式組件了。
2. Component
2.1 BrowserRouter
- 說明:
<BrowserRouter>
用於包裹整個應用。 - 示例代碼:index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter} from "react-router-dom"
import App from './App';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
,document.getElementById('root')
);
2.2 HashRouter
- 說明:作用和
<BrowserRouter>
一樣, 但是<HashRouter>
修改的是地址的hash值。 - 備注:6.x版本中
<BrowserRouter>
與<HashRouter>
的用法與5.x相同。
2.3 <Routes />
和<Route />
-
V6版本中移除了先前的
Switch
,引入了全新的替代者Routes
; -
Routes
和Route
要搭配使用,並且必須要用Routes
包裹Route
; -
Route
相當於一個if語句,如果路徑與當前URL匹配,則呈現其對應的組件。 -
<Route caseSensitive>
屬性用於指定:匹配時是否區分大小寫(默認為false)。 -
當URL發生變化時,
<Routes>
都會查看其所有子<Route>
元素以找到最佳匹配並呈現組件。 -
<Route>
也可以嵌套使用,且可以配合useRoutes()
配置“路由表”,但需要通過<Outlet>
組件來渲染其子路由。 -
示例代碼:
<Routes>
<Route path='/about' element={<About />} />
<Route path='/home' element={<Home />} />
<Route path='/' element={<Navigate to='/about'/>}/>
</Routes>
2.4 <Link>
-
作用: 修改URL, 且不發送網絡請求(路由鏈接).
-
注意: 外側需要用
<BrowserRouter>
或<HashRouter>
包裹 -
示例代碼:
import {Link} from 'react-router-dom' function Test() { return ( <div> <Link to="/路徑">按鈕</Link> </div> ) }
2.5 <NavLink>
- 作用: 與
<Link>
組件類似, 且可實現導航的"高亮"效果.
2.6 <Navigate>
- 作用:只要
<Navigate>
組件被渲染,就會修改路徑,切換視圖。 replace
屬性用於控制跳轉模式 (push 或 replace,默認是push)
2.7 <Outlet>
- 當
<Route>
產生嵌套時,渲染其對應的后續子路由。 - 在后續路子由組件的想要展示的位置上使用
<Outlet />
, 即可渲染。
3. 上課筆記
1. 一級路由
首先需要安裝react路由包: npm i react-router-dom
-
使用路由:在App.jsx中從
react-router-dom
中引入BrowserRouter
來包裹App
組件 -
創建路由鏈接:可以使用
react-router-dom
中的link
和NavLink
來創建路由鏈接,其中NavLink
可具有高亮效果。
以前我們的應用如果需要在各個頁面之間切換,使用錨點元素實現的話,在每次點擊時,頁面會被重新加載,React Router提供了 和
組件最終會被渲染成HTML標簽的 , 它的 to、query、hash 屬性會被組合在一起並渲染為 href 屬性。雖然 Link 被渲染為超鏈接,但在內部實現上使用腳本攔截了瀏覽器的默認行為,然后調用了history.pushState 方法。來避免這種情況的發生。當你點擊時,url會更新,組件會被重新渲染,但是頁面不會重新加載。
是的一個特定版本,會在匹配上當前的 url的時候給已經渲染的元素添加參數,組件的屬性有:
activeClassName(string):設置選中樣式,默認值為active- 需要將className寫成一個函數:
- activeStyle(object):當元素被選中時,為此元素添加樣式
- exact(bool):為true時,只有當導致和完全匹配class和style才會應用
- strict(bool):為true時,在確定為位置是否與當前URL匹配時,將考慮位置pathname后的斜線
- isActive(func)判斷鏈接是否激活的額外邏輯的功能
————————————————
版權聲明:本文為CSDN博主「冰雪為融」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/lhjuejiang/article/details/80366839
- 注冊路由:使用的組件由
SWitch
(已刪除)改為Routes
,還要需要使用Route
,Route
是用來被包裹的,一個<Routes>
來包裹多個<Route>
, 語法為:
router path 代表的是路由鏈接地址,React Component代表的是如果匹配成功所使用的組件名字。
<Route path="/router path" element={<React Component/>}>
2. 重定向
當我們什么路由鏈接都沒輸入,就相當於是'/'時,就會出現警告,No routes matched location "/", 這個時候我們就需要使用重定向來解決問題。
使用的組件由Redirect
改為Navigate
,語法為, 其中about為匹配不到路徑時所跳轉到的組件:
<Route path='/' element={<Navigate to="/about" />} />
Navigate
組件只要渲染就會引起視圖的切換,可以用此特性來控制當頁面達到某一條件時,啟用Navigate
組件來進行視圖切換,舉一個小例子
import React, {useState} from 'react'
import { Navigate } from 'react-router-dom'
export default function Home() {
const [count,setCount] = useState(0)
return (
<div>
<h3>我是Home的內容</h3>
{
count === 2 ? <Navigate to='/about'/> : <h4>當前count值是{count}</h4>
}
<button onClick={() => setCount(2)}>點我將count變為2</button>
</div>
)
}
其實Navigate
組件中還有一個屬性,replace, 可以控制跳轉的模式,默認為false, 即push模式。
<Route path='/' element={<Navigate to="/about" replace/>} />
3. NavLink高亮
NavLink路由鏈接在點擊的時候,會給他加一個class屬性,值默認是active,在使用bootstrap的時候就會出現高亮效果。
首先我們要知道在我們點擊一個連接的時候,會傳入一個對象,里面有isActive屬性,值為true。
利用這個特性我們可以寫一個函數來計算樣式,然后在className中使用這個函數,關鍵代碼如下:
function computedClassName({isActive}) {
return isActive? 'list-group-item atguigu': 'list-group-item'
}
<div className="list-group">
{/* 路由鏈接 */}
<NavLink className={computedClassName} to="/about">About</NavLink>
<NavLink className={computedClassName} to="/home">Home</NavLink>
</div>
4. useRoutes重定向
之前我們是這樣注冊路由的:
<Routes>
<Route path='/about' element={<About />} />
<Route path='/home' element={<Home />} />
<Route path='/' element={<Navigate to='/about'/>}/>
</Routes>
其實可以發現中間除了path值和element值不一樣以外,基本都是相同的結構,所以我們就可以使用useRoutes來注冊路由。
在我們有路由的項目中,一般會有兩個特殊的文件夾,一個是pages,里面存放的是各個路由的組件。另外一個是routes,里面存放的是路由表,里面的index.js一般是如下類似代碼:
import About from '../pages/About'
import Home from '../pages/Home'
import { Navigate } from 'react-router-dom'
// 創建路由表,可以用來注冊路由
const routerList = [
{
path:'/about',
element:<About />
},
{
path:'/home',
element:<Home />
},
{
path:'/',
element:<Navigate to='/about'/>
},
]
export default routerList;
然后我們只需要在需要使用注冊路由的組件里使用useRoutes
Hooks來實現了:
import {NavLink,useRoutes} from "react-router-dom"
export default function App() {
// 根據路由表生成對應的路由
const element = useRoutes(routerList)
......
{/* 路由鏈接 */}
<NavLink className='list-group-item' to="/about">About</NavLink>
<NavLink className='list-group-item' to="/home">Home</NavLink>
{/* 注冊路由 */}
{element}
......
}
這樣做的好處是可以把整個應用所有的路由都可以在routes文件夾下進行統一的管理,而且能夠讓代碼可讀性更好,也契合了未來Hooks發展的方向。
5. 嵌套路由
outlet
Outlet
像是一個槽位,如果匹配上了就在Outlet
組件所在的地方進行組件的展示,也就是說Outlet
可以指定組件呈現的位置。
to
to
屬性內可以直接寫最終地址,比如之前是/home/news
, 現在可以直接寫news
,注意不要寫成/news
, 否則就成了從一級路由news里找,即從根路徑下開始找。
routes/index.js
import About from '../pages/About'
import Home from '../pages/Home'
import { Navigate } from 'react-router-dom'
import Message from '../pages/Message'
import News from '../pages/News'
// 創建路由表,可以用來注冊路由
const routerList = [
{
path:'/about',
element:<About />
},
{
path:'/home',
element:<Home />,
children:[
{
path:'news',
element:<News/>
},
{
path:'message',
element:<Message/>
}
]
},
{
path:'/',
element:<Navigate to='/about'/>
}
]
export default routerList;
Home.jsx關鍵代碼:
import React from 'react'
import { NavLink, Outlet } from 'react-router-dom'
export default function Home() {
return (
<div>
<h3>我是Home的內容</h3>
<div>
<ul className='nav nav-tabs'>
<li>
<NavLink className='list-group-item' to='news'>News</NavLink>
</li>
<li>
<NavLink className='list-group-item' to='message'>Message</NavLink>
</li>
</ul>
{/* 指定路由組件呈現的位置 */}
<Outlet />
</div>
</div>
)
}
一共有三種路由路徑的書寫方式,以二級路由home組件下的news為例:
- to='/home/news'
- to='news'
- to='./news'
end
還有一個值得一提的事是,目前我們頁面所呈現的高亮的地方不僅有news, 而且還有一級路由home也是高亮的,我們如果不想讓他高亮,那么就可以在該組件上加一個屬性end
,來代表當匹配的是該路由的子路由時,該路由不高亮。
<NavLink className='list-group-item' to="/home" end>Home</NavLink>
6. 路由的params參數以及useMatch鈎子
一共有三種方式可以在路由進行傳參操作:1. params參數 2. search 3. location.state
我們首先講第一種,使用params參數:
// 1.Link路由鏈接的書寫方式
<Link to={`detail/${message.id}/${message.title}/${message.content}`}>{message.title}</Link>
// 2.路由表匹配規則
{
path:'detail/:id/:title/:content',
element:<Detail />
}
// 接收使用
import { useParams } from "react-router-dom"
export default function Detail() {
// 接收得到的參數是一個對象,我們可以使用結構的方式來獲得他
const { id, title, content } = useParams()
return (
<ul>
<li>消息編號:{id}</li>
<li>消息標題:{title}</li>
<li>消息內容:{content}</li>
</ul>
)
}
useMatch
我們還可以使用useMatch
鈎子來獲得之前match里面的參數,比如patten里的path參數等,具體使用語法如下,我們需要在所需要使用match參數的組件里把當前路徑包括params寫好:
import {useMatch} from "react-router-dom"
......
const match = useMatch('/home/message/detail/:id/:title/:content')
console.log(match)
7. 路由的search參數以及useLocation鈎子
一共有三種方式可以在路由進行傳參操作:1. params參數 2. search 3. location.state
我們來介紹第二種, 使用serach:
// 1. search傳參的書寫方式
messages.map(message => {
return (
// 路由鏈接
<li key={message.id}>
{/* search傳參 */}
<Link to={`detail?id=${message.id}&title=${message.title}&content=${message.content}`}>{message.title}</Link>
</li>
)
})
// 2.routes路由表不用改變任何東西
// 3.在接收參數的組件里,要使用useSearchParams hook來接收參數
import React from 'react'
import { useSearchParams } from 'react-router-dom'
export default function Detail() {
// 類似於useState的使用方式,所存放的數據在search.get('...')里
const [search, setSearch] = useSearchParams()
return (
<ul>
<li>消息編號:{search.get('id')}</li>
<li>消息標題:{search.get('title')}</li>
<li>消息內容:{search.get('content')}</li>
<li><button onClick={() => setSearch('id=008&title=哈哈&content=嘻嘻')}>點我更新一下search參數</button></li>
</ul>
)
}
useLocation
另外我們還可以使用useLocation
鈎子來獲得loaction的數據,里面包括了pathname和經過轉化后的search,具體的語法是:
import { useLocation } from 'react-router-dom'
......
const location = useLocation()
console.log(location);
8. 路由的state參數
一共有三種方式可以在路由進行傳參操作:1. params參數 2. search 3. location.state
我們來介紹第三種, 使用location.state,當然就是使用的上面提到過的useLocation
鈎子:
// 1. 路由鏈接
<li key={message.id}>
{/* state傳參 */}
<Link
to='detail'
state={{
id:message.id,
title:message.title,
content:message.content
}}
>{message.title}</Link>
</li>
// 2. routes路由表不需要做任何的改動,同search一樣
// 3. 在接收參數的組件里,要使用useLocation hook來接收參數
import React from 'react'
import { useLocation } from 'react-router-dom'
export default function Detail() {
const location = useLocation()
const { id, title, content } = location.state
return (
<ul>
<li>消息編號:{id}</li>
<li>消息標題:{title}</li>
<li>消息內容:{content}</li>
</ul>
)
}
9. 編程式路由導航
之前我們都是借助this.props.history
來對對象上的API對操作路由跳轉\前進和后退, 可是在函數式組件中我們並不能使用this, 這個時候我們借助useNavigate
這個Hook來實現.
首先我們來對其中的replace和state傳參來進行說明:
// 引入useNavigate鈎子
import { Link, Outlet,useNavigate } from 'react-router-dom'
// 使用鈎子,得到的navigate是一個函數
const navigate = useNavigate()
const showDetail = (message) => {
const {id, title, content} = message
navigate('detail',{
// 指定是否為替換的方式
replace:false,
// 傳遞state參數
state:{
id,
title,
content
}
})
}
// 在組件上使用函數來使用該navigate函數
<button onClick={() => showDetail(message)}>詳細信息</button>
但是我們知道在之前的react router5里面非路由組件是不能使用this.props.history
的, 但是在react router6里面, 我們只需要使用useNavigate
這個鈎子, 就可以實現非路由組件使用編程式路由導航, 並且可以實現頁面的回退和前進, 具體實現如下所示, components文件夾(此文件夾存放非路由組件)下的Header組件源代碼如下所示:
import React from 'react'
import { useNavigate } from 'react-router-dom'
export default function Header() {
const navigate = useNavigate()
const backward = () => {
navigate(-1)
}
const forward = () => {
navigate(1)
}
return (
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header">
<h2>React Router6 Demo</h2>
<button onClick={backward}>⬅后退</button>
<button onClick={forward}>➡前進</button>
</div>
</div>
)
}
10. useInRouterContext Hook的使用
作用: 如果組件在<Router>
的上下文中呈現, 則useInRouterContext
鈎子返回為 true
, 否則返回 false
.
比如說我們的App組件是被
11. useNavigationType() Hook的使用
- 作用:返回當前的導航類型(用戶是如何來到當前頁面的)
- 返回值:
POP
PUSH
REPLACE
- 備注:
POP
是指在瀏覽器中直接打開了這個路由組件(刷新頁面)
12. useOutlet()
- 作用, 用來呈現當前組件中要渲染的嵌套路由
- 示例代碼:
const result = useOutlet()
console.log(result)
// 如果嵌套路由沒有掛載,則result為null
// 如果嵌套路由已經掛載,則展示嵌套的路由對象
13. useResolvedPath()
- 作用: 給定一個url值, 解析其中的: path search 和 hash值.