bug收集:专门解决与收集bug的网站
网址:www.bugshouji.com
组件在项目开发过程经常发生变化,如:react-router-dom
今天为大家分享关于:React-router-dom v6.3 知识总结
一、路由模块的安装
npm install react-router-dom
// 目前版本: v6.3
官方案例:
代码语言:javascript复制import { render } from "react-dom";
import {
BrowserRouter,
Routes,
Route
} from "react-router-dom";
import App from "./App";
import Expenses from "./routes/expenses";
import Invoices from "./routes/invoices";
const rootElement = document.getElementById("root");
render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/expenses" element={<Expenses />} />
<Route path="/invoices" element={<Invoices />} />
</Routes>
</BrowserRouter>,
rootElement
);
二、路由各组件
1. BrowserRouter / HashRouter 相当于容器(类似router-view),用于指定路由的模式
BrowserRouter为history模式
HashRouter为hash模式
注意:BrowserRouter组件最好放在最顶层所有组件之外,这样能确保内部组件使用Link做路由跳转时不出错
如下:
代码语言:javascript复制function App() {
return (
<Router>
<Routes>
<Route path="/product/:id" element={<ProductDetails/>}></Route>
<Route path="/home" element={<StudentList />}></Route>
</Routes>
</Router>
);
}
2. Route 定义具体的路由
<Route path="/expenses" element={<Home/>} />
path 为路由名 , element 为对应的组件
注:element 的值 必须 写成标签的形式
3. 老版本V5 中的作用路由
示例:
代码语言:javascript复制<BrowserRouter>
<Route path="/" component={ Home } />
<Route path="/product" component={ Product } />
</BrowserRouter>
如上代码:
在当用户输入/product时,将会匹配到两个路由,/ 及 /product ;则会显示两个组件 ;
原因是老版本路由在匹配时,是进行模糊匹配
解决方案:
步骤1:使用Switch让路由只能匹配一个; 注意顺序问题,路由先从上向下进行匹配
代码语言:javascript复制<BrowserRouter>
<Switch>
<Route path="/" element={<Home />} />
<Route path="/product" element={<Product />} />
</Switch>
</BrowserRouter>
步骤2:使用exact关键字,让路由进行精准匹配
<Route path="/" exact component={Home} />
加上以上关键字,路由将会精准匹配,只会匹配,path为”/" 的路由
4. V6中的 组件Routes
v6 中 Switch 名称变为 Routes , 且Route 标签必须包含在Routes标签里,会不然报错
也就是说,路由只能匹配到一个,不会在出现多个路由匹配的情况
5. v6 中,exact 属性不再需要
v6 内部算法改变,不再需要加exact实现精确匹配路由,默认就是匹配完整路径。
如果需要旧的行为(模糊匹配),路径后加/*
<Route path="/products/*" element={<Products />} />
<Route path="/products/:productId" element={<ProductDetail />} />
测试: /prodcuts 显示
/products/4 显示
/products/haha 显示
/products/haha/hehe 显示
结论:看第6点:React Router 能够自动找出最优匹配路径 ,顺序不重要
若:path属性取值为*时,可以匹配任何(非空)路径,同时该匹配拥有最低的优先级。可以用于设置404页面。
代码语言:javascript复制<Routes>
<Route path='/foo' element={Foo}>
<Route path='bar' element={Bar}></Route>
<Route path='*' element={NotFound}></Route>
</Route>
</Routes>
6. v6 中,Route 先后顺序不再重要,React Router 能够自动找出最优匹配路径
7. v6 保留Link,NavLink
Link,NavLink 类似与a标准,区别NavLink可以设置高亮样式
<Link to="/home">首页</Link>
NavLink的使用,及激活状态的样式设置
V5老版本,activeClassName设置,或activeStyle
<NavLink to="/" activeClassName='active-menu'>
<i className="fa fa-dashboard"></i>
<span>首页</span>
</NavLink>
V6新版本,activeClassName 与 activeStyle属性被移除
可以直接在的className和style中使用一个函数来设置激活状态的样式。
方法:通过箭头函数接收到isActive参数值,通过isActive的值来设置
通过className
代码语言:javascript复制<NavLink
to="/faq"
className={({ isActive }) =>
isActive ? 'active' : ''
}
>
首页
</NavLink>
通过style
代码语言:javascript复制<NavLink to="/product/1" style={({ isActive }) => {
return {
fontWeight: "bold",
color: isActive ? "red" : ""
};
}}
fontWeight: "bold" 不管是否激活,都会有; 因为没有判断
8. Navigate组件
代码语言:javascript复制<Route path="/" element ={<Navigate replace to="/home" />} />
<Navigate replace to="" />是对旧的 Redirect 的完整取代。
replace 属性也可以省略,不过行为由 replace 改为 push
replace vs push
this.props.history.push('router地址')
push: a-b-c,可以回到上一级
push跳转会形成history,可返回到上一层。
this.props.history.replace('router地址')
replace: a-b-c 回不到上一级 适用于登录后,不需要重新回到登页面
replace跳转不会形成history,不可返回到上一层。
结论: push有历史记录,replace没有历史记录
9. V6中嵌套路由改为相对路径
嵌套路由必须放在 中,且使用相对路径,不再像 v5 那样必须提供完整路径,因此路径变短。
代码语言:javascript复制<Route path='/about' element={<About />}>
<Route index element={<Address />} />
<Route path='address' element={<Address />}></Route>
<Route path='information' element={<Information />}></Route>
<Route path='joinus' element={<Join />}></Route>
</Route>
上面的访问路径为 /about/address , /about/information, /about/joinus
10. 使用Outlet组件
此组件是一个占位符,告诉 React Router 嵌套的内容应该放到哪里。
代码语言:javascript复制export default class about extends Component {
render() {
return (
<div className='container'>
<h2>关于</h2>
<div>
<div className="left">
<ul>
<li><Link to='/about/address'>公司地址</Link></li>
<li><Link to='/about/join'>加入我们</Link></li>
<li><Link to='/about/story'>背景故事</Link></li>
</ul>
</div>
<div className="left">
<Outlet/>
</div>
</div>
</div>
)
}
}
11. 使用index 指定默认路由, 或者path为空
代码语言:javascript复制<Route path='/about' element={<About />}>
<Route index element={<Address />} />
<Route path='address' element={<Address />}></Route>
<Route path='information' element={<Information />}></Route>
<Route path='joinus' element={<Join />}></Route>
</Route>
或者
设置path为空,来指定默认路由
代码语言:javascript复制let router =[{
path: "/home",
element :<Home/ >,
children: [
{
path:"",
element:<News/>
},
{
path: " news " ,
element:<News/>
}
]
}]
12. useRoutes 声明式的路由配置方式
声明式路由中,不能写index, 可以让path: "" , 来实现显示默认组件;
useRoutes函数,会返回已经渲染好的路由元素
代码语言:javascript复制const GetRoutes=()=>{
return useRoutes([
{
path:'/',
element:<Home/>
},
{
path:'/home',
element:<Home/>
},
{
path:'/product',
element:<Product/>
},
{
path:'/about',
element:<About/>,
children:[
{
path:"",
element:<Story/>
},
{
path:'address',
element:<Address/>
},
{
path:'join',
element:<Join/>
},
{
path:'story',
element:<Story/>
}
]
},
{
path:'/concat',
element:<Concat/>
},
{
path:'/brand',
element:<Brand/>
}
])
}
function App() {
return (
<div>
<Router>
<Nav></Nav>
<GetRoutes/>
{/* <Routes>
<Route path='/' element={<Home/>}></Route>
<Route path='/home' element={<Home/>}></Route>
<Route path='/product' element={<Product/>}></Route>
<Route path='/about' element={<About/>}>
<Route index element={<Story/>}></Route>
<Route path='address' element={<Address/>}></Route>
<Route path='join' element={<Join/>}></Route>
<Route path='story' element={<Story/>}></Route>
</Route>
<Route path='/concat' element={<Concat/>}></Route>
<Route path='/brand' element={<Brand/>}></Route>
</Routes>*/}
</Router>
</div>
);
}
export default App;
13. v6 用useNavigate实现编程式导航,useHistory被移除
代码语言:javascript复制import {useNavigate} from "react-router-dom";
const navigate = useNavigate();
navigate("/welcome"); //push
如果要重定向:
navigate("/welcome",{replace:true});
除此之外,还可以使用navigate(-1)后退到前一页,使用navigate(-2)后退到前一页的前一页,navigate(1)前向导航,
注:V5版本中的编程式路由导航 this.props.history.replace() 与 this.props.history.push();
在V6中useNavigate 替代
详细版本:
代码语言:javascript复制// v6版本编程导航使用 useNavigate (以下为引入代码)
import { useNavigate } from "react-router-dom";
export default function A() {
const navigate = useNavigate();
//...
}
- push跳转 携带params参数
navigate(`/b/child1/{id}/{title}`);
2.push跳转 携带search参数
navigate(`/b/child2?id={id}&title=
3.push跳转 携带state参数
navigate("/b/child2", { state: { id, title }});
4.replace跳转 携带params参数
navigate(`/b/child1/{id}/{title}`,{replace: true});
5.replace跳转 携带search参数
navigate(`/b/child2?id={id}&title=
6.replace跳转 携带state参数
navigate("/b/child2", { state: { id, title },replace: true});
14. useSearch 获取路由参数的方法
在Route组件中的path属性中定义路径参数
在组件内通过useParams hook访问路径参数
代码语言:javascript复制<BrowserRouter>
<Routes>
<Route path='/foo/:id' element={Foo} />
</Routes>
</BrowserRouter>
import { useParams } from 'react-router-dom';
export default function Foo(){
const params = useParams();
return (
<div>
<h1>{params.id}</h1>
</div>
)
}
在以前版本中,组件的props会包含一个match对象,在其中可以取到路径参数。但在最新的6.x版本中,无法从props获取参数。
并且,针对类组件的withRouter高阶组件已被移除。
因此对于类组件来说,使用参数有两种兼容方法:
1. 将类组件改写为函数组件传递
2. 写一个HOC来包裹类组件,用useParams获取参数后通过props传入原本的类组件
15. useSearchParams 获取seach 参数
查询参数不需要在路由中定义
使用useSearchParams hook来访问查询参数。其用法和useState类似,会返回当前对象和更改它的方法
更改searchParams时,必须传入所有的查询参数,否则会覆盖已有参数
代码语言:javascript复制import { useSearchParams } from 'react-router-dom';
// 当前路径为 /foo?id=12
function Foo(){
const [searchParams, setSearchParams] = useSearchParams();
console.log(searchParams.get('id')) // 12
setSearchParams({
name: 'foo'
}) // /foo?name=foo
return (
<div>foo</div>
)
}
但在最新的6.x版本中,无法从props获取参数。在类组件中获取seach参数的值,解决方法与上面一样.
16. useLocation 获取传递的state值
1.传递参数
代码语言:javascript复制<NavLink to={`detail`} state={{
id:item.id,
name:item.name,
content: item.content }}>
{item.name}
</NavLink>
或
代码语言:javascript复制navigate("/b/child2", { state: { id, title }});
2.接收参数
代码语言:javascript复制import React from 'react'
import { useLocation } from 'react-router-dom'
export default function Detail() {
// 这是连续结构赋值 把useLocation里面呢的state解构,在解构state里面的属性
const {state:{id,name,content}} = useLocation()
return (
<div>
<ul>
<li>id:{id}</li>
<li>content:{content}</li>
<li>name:{name}</li>
</ul>
</div>
)
}
注: prop属性中的location已经没有了,所以在类组件不能获取到相应的数据了,
解决方案就是1. 写成函数 2. 使用高阶组件HOC (13,14,15,16 都是这样)
17. 多组路由
通常,一个应用中只有一个Routes组件。
但根据实际需要也可以定义多个路由出口(如侧边栏和主页面都要随URL而变化)
代码语言:javascript复制<Router>
<SideBar>
<Routes>
<Route></Route>
</Routes>
</SideBar>
<Main>
<Routes>
<Route></Route>
</Routes>
</Main>
</Router>
18. 路由组件懒加载
安装: npm i @loadable/component
代码语言:javascript复制import loadable from '@loadable/component'
const ComponentNode = loadable(()=>{
return import("./" item.componentPath)
})
<Route path={item.path} element={<ComponentNode />}>
苟有恒 , 何必三更眠五更起