react-router v5 升级 v6
⛄:最近在给项目从 react-router v5 升级到 v6,发现 v6 是一次重大更新,有很多的破坏性变更,我这里总结了一些常见的 API 替换方案,希望能帮到大家。
官方升级文档:https://reactrouter.com/en/main/upgrading/v5
升级 react-router 主要有以下收益:
react-router 包体积减小,20kb -> 8kb。
更小成本的使用 Error Boundaries,可在配置式路由中使用配置的方式在任意子路由接入 Error Boundaries。防止页面白屏,降低白屏率。
配置化路由,路由编写形式更加简洁,使用配置的方式一键生成路由。
更多的 hooks 替代原先的 props。
搭配 Remix 可以有更多的特性:
- 并行懒加载,在深层路由嵌套中,react-router v6 会并行请求所有子路由的资源,而不是像 v5 一样一级一级请求。提高加载速度,路由层级越深效果越明显。 升级步骤
升级步骤
- 执行命令
npm uninstall @types/react-router
,v6 版本使用 ts 重构,无需 ts 类型包。
- 执行命令
npm update react-router@6 react-router-dom@6
,升级 react-router 版本。
- 更换 API,可直接运行项目查看报错,依据报错位置一步步替换。下文列出了对应 API 的变更及替换方式,大家直接对照自己项目中旧的 API 在文中搜索即可😀。
@types/react-router-dom 升级为相同步骤。
API 变更
useHistory 使用 useNavigate 代替
- v6 中 useHistory 被移除,不再支持获取 histoy 对象,所有 history 对象上的属性及方法都需要替换。
- 常用的跳转方法需要使用 useNavigate 替换。
1 2 3 4 5 6 7 8 9
| import { useHistory } from 'react-router-dom'; const history = useHistory(); history.push('/tns', data); history.replace('/tns'); history.goBack(); history.goForward(); history.go(2)
|
1 2 3 4 5 6 7 8 9
| import { useNavigate } from 'react-router-dom'; const navigate = useNavigate(); navigate('/tns', { state: data }); navigate('/tns', { replace: true }); navigate(-1); navigate(1); navigate(2)
|
history.location 使用 useLocation 代替
1 2 3 4 5 6 7 8
| import { useHistory } from 'react-router'; const history = useHistory(); const location = history.location;
import { useLocation } from 'react-router'; const location = useLocation();
|
history.listen 使用 useEffect 监听 location 代替
- history.listen 中常用两个参数 location 与 action,分别可以使用 useLocation 与 useNavigationType 获取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { useHistory } from 'react-router'; const history = useHistory(); history.listen((location, action) => { });
import { useLocation, useNavigationType } from 'react-router-dom'; const location = useLocation(); const navigationType = useNavigationType(); useEffect(()=>{ }, [location, navigationType])
|
history.blocker 使用 useBlocker 代替
- history.blocker 统一使用 useBlocker 替换,useBlocker 监听函数中,返回 true 阻止跳转,返回 false 不阻止跳转。
- history.block 中用到的 location 与 action 参数使用 nextLocation historyAction 替换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { useHistory } from 'react-router'; const history = useHistory(); history.block((location , action) => { })
import { useBlocker } from 'react-router'; useBlocker(({ nextLocation, historyAction }) => { if (xxx) { return true; } return false; });
|
withRouter
- withRouter 在 v6 中移除。withRouter 主要是向组件中注入 history、location、match 这三个 props,需要观察被观察的组件是否用到了这三个 props,如果用到需要使用新的 hooks,分别使用 useNavigate、useLocation、useMatch 代替,最后删除 withRouter 即可。
Switch 替换为 Routes
- v6 中 Switch 被移除,直接替换为 Routes 即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { Route, Switch } from 'react-router-dom'; <Switch> <Route path="xxx"> <XXX /> </Route> </Switch>
import { Route, Routes } from 'react-router-dom'; <Routes> <Route path="xxx"> <XXX /> </Route> </Routes>
|
Redirect 替换为 Navigate
- Redirect v6 中被移除,使用 Navigate 传入 to 为重定向的地址进行跳转。
1 2 3 4 5
| <Redirect from={routePath} to={redirectPath} exact />
<Navigate to={redirectPath} />
|
Route 组件变更
- strict 被删除,path 末尾的 ‘/‘ 默认被忽略。
- exact 被删除,深度匹配在 path 末尾加 ‘/*’ 开启。
- sensitive 大小写敏感替换为 caseSensitive。
- children 中不再需要内容,替换为 element 用于传递子路由组件。
- path:react-router v6 中路径是相对的,path 声明时无需在起始处写 ‘/‘。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <Route key={routePath} path={routePath} sensitive={sensitive} strict={strict} exact={exact} > {children} </Route>
<Route key={routePath} path={routePath} caseSensitive={caseSensitive} element={children} />
|
RouteObject 配置式路由
- v5 版本仅能使用 jsx 进行路由的编写,在 v6 版本中可以升级为配置式路由。
- 父级路由中需要在内部使用
<Outlet />
组件,用于挂载子路由的入口。
- 路由配置变更与 Route 一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import { RouteObject } from 'react-router'; const routeConfig: RouteObject[] = [ { path: '/', Component: XXX, children: [ { path: 'xxx', ErrorBoundary: XXX, children: [ { path: 'xxx/*', lazy: () => import('xxx'), }, ], }, { path: '*', Component: NotFound, }, ], }, ]; export default routeConfig;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { createBrowserRouter, RouterProvider, } from "react-router-dom"; import routeConfig from 'xxx'; import Root, { rootLoader } from "./routes/root"; import Team, { teamLoader } from "./routes/team"; const router = createBrowserRouter(routeConfig); ReactDOM.createRoot(document.getElementById("root")).render( <RouterProvider router={router} /> );
|
useRouteMatch 使用 useMatch useMatchs 代替
- useRouteMatch 被移除,可使用 useMatch useMatchs 代替。
1 2 3 4 5 6 7 8 9 10 11
| import { useRouteMatch } from 'react-router';
const match = useRouteMatch();
import { useMatch, useMatches } from 'react-router';
const match = useMatch('/example');
const matches = useMatches();
|
使用 useSearchParams 获取路由参数
- v6 中新增 hooks 用于获取/设置 url 上的 query 参数
1 2 3 4 5 6 7 8 9 10 11
| import { useSearchParams } from 'react-router';
const [searchParams, setSearchParams] = useSearchParams();
const id = searchParams.get('id');
setSearchParams(setSearchParams);
|
Link 组件变更
- Link 组件将 to 传参拆出,且 path 支持相对路径的传递。
1 2 3 4 5 6 7 8 9 10 11 12
| import { Link } from "react-router-dom"; <Link to={{ pathname: "/home", state: state }} />
import { Link } from "react-router-dom"; <Link to="/home" state={state} />
<Link to="..">All Users</Link> <Link to=".">User Profile</Link> <Link to="../mj">MJ</Link>
|
NavLink 组件变更
- 原先的 exact 参数替换为 end。
- activeClassName 与 activeStyle 被删除,可以向 NavLinke className 与 style 传递函数代替。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <NavLink to="/messages" style={{ color: 'blue' }} activeStyle={{ color: 'green' }} className="nav-link" activeClassName="activated" > Messages </NavLink>
<NavLink to="/messages" style={({ isActive }) => ({ color: isActive ? 'green' : 'blue' })} className={({ isActive }) => 'nav-link' + (isActive ? 'activated' : '')} > Messages </NavLink>
|
结语
以上就是 react-router
v5 升级 v6 时常见的 API 替换方式了,如果你有一些不理解的地方可以积极评论😀。
如果对你有帮助的话记得帮我点个赞 👍。
文章内容有不正确的地方请指出,我会及时更改 ⛄。