都说react-router东西不多,但是怎么说也是react生态中不可获取的一环,就算不去深入了解,那么起码得需要知道它的一些api和用法。毕竟也用了这么久,我自认为是会用的,但是v6版本的出现还是让我认清自己,不能只专注于表面,并且在新版本或者技术出现的时候,要给与一定的关注。
版本主要更改
1.改为变为
其实算是一个重命名,改动不大
2.属性更改
主要体现在component改成了element,并且需要用组件标签引入
// 之前的route
<Route path="/" component={Home}/>
// 现在的
<Route path="/" element={<Home />}/>
3. 删除了Redirect
原来的Redirect大家也都用习惯了,觉得很好用,但是v6把它给删了!!! 但是没事,我们还有其他方案。
import { Routes, Route, Navigate } from 'react-router-dom'
<Routes>
<Route path="*" element={<Navigate to="/home" />} />
</Routes>
4. 嵌套路由方式更改
4.1 路由嵌入方式更改,使用了新api Outlet
// routers.js
<Route path='/user' element={<user />}>
<Route path='/list' element={<userList />} />
</Route>
// user页面内
import { Outlet } from 'react-router-dom'
const User = ()=>{
return (
<div>
这是一级页面
<Outlet/>
这是二级页面的内容,展示匹配的路由页面组件内容
</div>
)
}
4.2 嵌套编写方式
不需要再使用useRouteMatch去填充path了。
// 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的
// v6
import {
BrowserRouter,
Routes,
Route,
Link,
Outlet
} from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="profile/*" element={<Profile/>} />
</Routes>
</BrowserRouter>
);
}
function Profile() {
return (
<div>
<nav>
<Link to="me">My Profile</Link>
</nav>
<Routes>
<Route path="me" element={<MyProfile />} />
<Route path=":id" element={<OthersProfile />} />
</Routes>
</div>
);
}
4.3 可多次嵌套写switch(Routes)
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>
);
}
5. 用useNavigate代替useHistory
也是类似于名字更改,不一样的是实例的方法也不太一样了
// v5
history.push('/home');
history.replace('/home');
// v6
navigate('/home');
navigate('/home', {replace: true});
6. 新钩子useRoutes代替react-router-config
再用react-router-config配合v6就发现报错了,现在v6用的是useRoutes,有点坑,我以为只是名字一改,结果大错特错,下面是我的踩坑过程
// v5 config用法
import { HashRouter } from "react-router-dom";
import { renderRoutes } from 'react-router-config'
import routers from "@/routers";
function App() {
return (
<HashRouter>
{renderRoutes(routers)}
</HashRouter>
);
}
到了v6,改用useRoutes之后,我以为的↓
// 我以为的
import { HashRouter, useRoutes } from "react-router-dom";
import routers from "@/routers";
function App() {
return (
<HashRouter>
{useRoutes(routers)}
</HashRouter>
);
}
结果当然报错了
我一看错误提示,必须在下面。。。
// 馊主意
import { HashRouter, useRoutes, Router } from "react-router-dom";
import routers from "@/routers";
function App() {
return (
<HashRouter>
<Router>
{useRoutes(routers)}
</Router>
</HashRouter>
);
}
这个更不用说,肯定还是错的,也是报一样的错误,虽然语义上理解没什么问题。于是我上github router项目上的api去看看用法,原来有实例,我照猫画虎得到如下
// 官方提供
import { useRoutes } from "react-router-dom";
import routers from "@/routers";
function App() {
const rt = useRoutes(routers)
return rt
}
结果竟然还是错的,一样的报错信息,没道理啊,后来还是百度出来了最终方案,看起来不少人碰到了这个坑
// 最终可行方案
import { HashRouter, useRoutes } from "react-router-dom";
import routers from "@/routers";
function Rout(){
const rt = useRoutes(routers)
return rt
}
function App() {
return (
<HashRouter>
<Rout/>
</HashRouter>
)
}
终于成了
7. 包的大小减少了
从20kb到8kb,肯定有很多优化,很多奇思妙想吧
8. 路径格式变化
不再支持正则的匹配,而仅支持2种占位符:动态:id样式参数和*通配符。 并且会在匹配的时候默认忽略所有url末尾的/。 现在的link to的url,非常的类似cd
当前路径:"/users",则<Link to="me">将跳转<a href="/users/me">。
当前路径:"/users",则<Link to="../me">将跳转<a href="/me">。
//v5
当前路径:"/users",则<Link to="me">将跳转<a href="/me">。
当前路径:"/users/",则<Link to="me">将跳转<a href="/users/me">。
如何在6下使用懒加载
如何在上面的改造后再使用懒加载呢
// v5版本
// App.js
import { Suspense } from "react";
<Suspense fallback={renderLoader()}>{renderRoutes(routes)}</Suspense
// 路由表,router.js
import { lazy } from "react";
//...
{
path: '/',
exact: true,
component: lazy(() => import('@/pages/Home')),
},
v6也可以这么做,但是就不能再使用useRoute了,需要自己手动去map路由表
// v6的循环map路由
<Routes>
{
routers.map((item, i) => {
return (
<Route key={i} path={item.path} element={
<Suspense fallback={
<div>路由懒加载...</div>
}>
<item.element />
</Suspense>
} />
)
})
}
</Routes>
还有另外一种方式 三方包了------react-loadable
// 路由表router.js
import React from 'react'
import loadable from 'react-loadable' //引入这个loadable,使用这个来加载路由
const LoadingTip = () => <div>懒加载路由ing...</div>
// 如果你是js就直接无视这个: Array<Router>的类型限定
const router = [
{
path: '/',
component: loadable({
loader: () => import('@/views/home'), // 需要异步加载的路由
loading: LoadingTip // 这是一个的提示
})
},
{
path: '/about',
component: loadable({
loader: () => import('@/views/about'),
loading: LoadingTip
})
}
]
export default router
// APP.js
<Routes>
{
router.map((item, i) => {
return (
<Route
key={i}
path={item.path}
element={ < item.component /> }
/>
)
})
}
</Routes>
参考:浅析React Router V6 useRoutes的使用 react-router仓库 React-Router v6 新特性解读及迁移指南 react-router-dom v6的路由懒加载形式,这里写了两种