react-router v5 升级 v6
react-router v5 升级 v6
⛄:最近在给项目从 react-router v5 升级到 v6,发现 v6 是一次重大更新,有很多的破坏性变更,我这里总结了一些常见的 API 替换方案,希望能帮到大家。
升级 react-router 主要有以下收益:
-
react-router 包体积减小,20kb -> 8kb。
-
更小成本的使用 Error Boundaries,可在配置式路由中使用配置的方式在任意子路由接入 Error Boundaries。防止页面白屏,降低白屏率。
-
配置化路由,路由编写形式更加简洁,使用配置的方式一键生成路由。
-
更多的 hooks 替代原先的 props。
-
- 并行懒加载,在深层路由嵌套中,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 替换。
// v5
import { useHistory } from 'react-router-dom';
const history = useHistory();
history.push('/tns', data);
history.replace('/tns');
history.goBack();
history.goForward();
history.go(2)
// v6
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 代替
// v5
import { useHistory } from 'react-router';
const history = useHistory();
const location = history.location;
// v6
import { useLocation } from 'react-router';
const location = useLocation();
history.listen 使用 useEffect 监听 location 代替
- history.listen 中常用两个参数 location 与 action,分别可以使用 useLocation 与 useNavigationType 获取。
// v5
import { useHistory } from 'react-router';
const history = useHistory();
history.listen((location, action) => {
// ...
});
// v6
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 替换。
// v5
import { useHistory } from 'react-router';
const history = useHistory();
history.block((location , action) => {
// ...
})
// v6
import { useBlocker } from 'react-router';
useBlocker(({ nextLocation, historyAction }) => {
if (xxx) {
return true; // 返回 true 阻止当前跳转
}
return false; // 返回 false 不进行阻止跳转
});
withRouter
- withRouter 在 v6 中移除。withRouter 主要是向组件中注入 history、location、match 这三个 props,需要观察被观察的组件是否用到了这三个 props,如果用到需要使用新的 hooks,分别使用 useNavigate、useLocation、useMatch 代替,最后删除 withRouter 即可。
Switch 替换为 Routes
- v6 中 Switch 被移除,直接替换为 Routes 即可。
// v5
import { Route, Switch } from 'react-router-dom';
<Switch>
<Route path="xxx">
<XXX />
</Route>
</Switch>
// v6
import { Route, Routes } from 'react-router-dom';
<Routes>
<Route path="xxx">
<XXX />
</Route>
</Routes>
Redirect 替换为 Navigate
- Redirect v6 中被移除,使用 Navigate 传入 to 为重定向的地址进行跳转。
// v5
<Redirect from={routePath} to={redirectPath} exact />
// v6
<Navigate to={redirectPath} />
Route 组件变更
- strict 被删除,path 末尾的 '/' 默认被忽略。
- exact 被删除,深度匹配在 path 末尾加 '/*' 开启。
- sensitive 大小写敏感替换为 caseSensitive。
- children 中不再需要内容,替换为 element 用于传递子路由组件。
- path:react-router v6 中路径是相对的,path 声明时无需在起始处写 '/'。
// v5
<Route
key={routePath}
path={routePath}
sensitive={sensitive} // 大小写是否敏感替换为 caseSensitive
strict={strict} // strict 被删除了 末尾的'/'会被忽略
exact={exact} // exact 被删除了 需要进行深度匹配在末尾加* path/*
>
{children}
</Route>
// v6
<Route
key={routePath}
path={routePath}
caseSensitive={caseSensitive}
element={children}
/>
RouteObject 配置式路由
- v5 版本仅能使用 jsx 进行路由的编写,在 v6 版本中可以升级为配置式路由。
- 父级路由中需要在内部使用
<Outlet />
组件,用于挂载子路由的入口。 - 路由配置变更与 Route 一致。
import { RouteObject } from 'react-router';
const routeConfig: RouteObject[] = [
{
path: '/',
Component: XXX, // 该路由下挂载的组件
children: [
{
path: 'xxx',
ErrorBoundary: XXX, // 异常捕获组件
children: [
{
path: 'xxx/*',
// 懒加载,需要文件中导出 Component 命名的组件
lazy: () => import('xxx'),
},
],
},
{
path: '*',
Component: NotFound,
},
],
},
];
export default routeConfig;
// 使用 createBrowserRouter 与 RouterProvider 消费配置式路由
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 代替。
// v5
import { useRouteMatch } from 'react-router';
// 获取到当前的路由匹配的 match 对象
const match = useRouteMatch();
// v6
import { useMatch, useMatches } from 'react-router';
// 单独获取 match 对象需要传入 path
const match = useMatch('/example');
// 获取从根路由到当前路由的全部 matches 对象
const matches = useMatches();
使用 useSearchParams 获取路由参数
- v6 中新增 hooks 用于获取/设置 url 上的 query 参数
import { useSearchParams } from 'react-router';
// searchParams 获取参数
// setSearchParams 变更参数
const [searchParams, setSearchParams] = useSearchParams();
// 获取参数 id
const id = searchParams.get('id');
// 传入 setSearchParams 变更 searchParams
setSearchParams(setSearchParams);
Link 组件变更
- Link 组件将 to 传参拆出,且 path 支持相对路径的传递。
// v5
import { Link } from "react-router-dom";
<Link to={{ pathname: "/home", state: state }} />
// v6
import { Link } from "react-router-dom";
<Link to="/home" state={state} />
// 支持相对 path 的形式
<Link to="..">All Users</Link>
<Link to=".">User Profile</Link>
<Link to="../mj">MJ</Link>
NavLink 组件变更
- 原先的 exact 参数替换为 end。
- activeClassName 与 activeStyle 被删除,可以向 NavLinke className 与 style 传递函数代替。
// v5
<NavLink
to="/messages"
style={{ color: 'blue' }}
activeStyle={{ color: 'green' }}
className="nav-link"
activeClassName="activated"
>
Messages
</NavLink>
// v6
<NavLink
to="/messages"
style={({ isActive }) => ({ color: isActive ? 'green' : 'blue' })}
className={({ isActive }) => 'nav-link' + (isActive ? 'activated' : '')}
>
Messages
</NavLink>
结语
以上就是 react-router
v5 升级 v6 时常见的 API 替换方式了,如果你有一些不理解的地方可以积极评论😀。
如果对你有帮助的话记得帮我点个赞 👍。
文章内容有不正确的地方请指出,我会及时更改 ⛄。
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 LonelySnowman
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果