TODO 内部分享文字稿,有时间需要斟酌文笔以及要点准确性
原文链接
(https://github.com/remix-run/react-router/blob/main/docs/upgrading/v5.md)[https://github.com/remix-run/react-router/blob/main/docs/upgrading/v5.md]%5Bhttps://github.com/remix-run/react-router/blob/main/docs/upgrading/v5.md%5D)
注:本文带有部分我的主观意识,删除了一些自认为不重要的内容,详细推荐阅读原文。
按照惯例提前总结全文关键内容,感兴趣可以下滑详细阅读。
升级的前提:
router 团队建议先升级到 5.1 版本并使用新的 API 来渐进式升级到 v6
不再兼容 react v16.8 以下版本
主要改动内容:
废弃
Switch组件,由Routes代替(使用了智能匹配路径算法)废弃
Redirect组件,由Navigate代替废弃
useHistory方法,由useNavigate代替Route组件移除原有component及render属性,统一通过element属性传递:<Route element={<Home />}>Route组件支持嵌套写法(v3 版本用法回归)Route组件的path规则变更,不再支持类正则写法消除了
v5版本中带后斜杠的路径时,Link组件的跳转模糊的问题Link组件支持自动携带当前父路由,以及相对路径写法../home新增
useRoutes方法,代替之前的react-router-config写法,同样支持嵌套其他一些 API 名称变更
React Router v6 makes heavy use of React hooks, so you'll need to be on React 16.8 or greater before attempting the upgrade to React Router v6. The good news is that React Router v5 is compatible with React >= 15, so if you're on v5 (or v4) you should be able to upgrade React without touching any of your router code.
新版本大量使用 hooks,所以必须要安装 16.8 版本以上的 react。
目前大多数 react 项目都已经使用 17 版本了,没什么可说的。至于巨石项目,还是暂时先死了这条心...
It will be easier to make the switch to React Router v6 if you upgrade to v5.1 first. In v5.1, we released an enhancement to the handling of elements that will help smooth the transition to v6. Instead of using and props, just use regular element everywhere and use hooks to access the router's internal state.
react router 团队建议先升级到 v5.1 版本,并采用一些新的 API,有助于渐进式升级到 v6。
不过我都想要升级了,还在乎那一哆嗦吗(主要还是为了巨石..)
在 5.1 版本之前的使用方法
import { Switch, Route } from 'react-router-dom';
const User = ({ id }: { id: string }) => {
return <div>user id: {id}</div>;
};
const App = () => {
return (
<Switch>
<Route exact path="/" component={Home} />
<Route path="/user/:id" render={(route) => <User id={route.match.params.id} />} />
</Switch>
);
};
5.1 推荐用法
import { Switch, Route, useParams } from 'react-router-dom';
const User = () => {
const { id } = useParams<{ id: string }>();
return <div>user id: {id}</div>;
};
const App = () => {
return (
<Switch>
<Route exact path="/">
<Home />
</Route>
{/* 同时支持props.children属性传递 */}
<Route path="/user/:id" children={<User />} />
</Switch>
);
};
In general, React Router v5.1 (and v6) favors elements over components (or "element types"). There are a few reasons for this, but we'll discuss more further down when we discuss v6's API.
5.1 版本之后,react router 更加倾向于 ReactElement 类型而不是 ReactComponent 类型,在后面的文档会详细介绍
When you use regular React elements you get to pass the props explicitly. This helps with code readability and maintenance over time. If you were using to get a hold of the params, you can just useParams inside your route component instead.
useParams()比<Route render={(route) => <User id={route.match.params.id} />}>可读性以及维护性更好。
Along with the upgrade to v5.1, you should replace any usage of withRouter with hooks. You should also get rid of any "floating" elements that are not inside a . Again, the blog post about v5.1 explains how to do this in greater detail.
在 5.1 版本中,应该使用 hooks 代替 withRouter,也应该移除掉在 Switch 外部的 Route 节点。
总之,升级到 5.1 之后需要做以下几件事情:
使用
<Route children>替换<Route render>或<Route children>使用
hooks获取当前 router 信息,例如useLocation()或useParams()移除
withRouter装饰器写法将在
<Switch>外部的<Route>统一替换为useRouteMatch或将他们挪到<Switch>中
If you want to redirect on the initial render, you should move the redirect logic to your server (we wrote more about this here).
如果需要初始化渲染的时候就执行重定向,推荐将重定向逻辑放在服务端实现「详细说明」。
文章中描述了几点初始化时重定向的弊端,主要如下:
客户端并不是真正的重定向,此时的 HTTP 状态码是 200。爬虫读取页面时并不会执行客户端的重定向方法,不利于 SEO
在 SSR 时,执行
ReactDOMServer.renderToString()得到的结果是一次重定向,浪费时间和资源
If you want to redirect client-side, move your into a prop.
客户端执行重定向推荐使用 Route 的 render 属性来渲染 Redirect
// 5.1 之前
<Switch>
<Redirect from="about" to="about-us" />
</Switch>
// 5.1
<Switch>
<Route path="about" render={() => <Redirect to="about-us" />} />
</Switch>
Normal elements that are not inside a are ok to remain. They will become elements in v6.
这是第一个破坏性变更:在 v6 版本中废弃Redirect,由Navigate代替。
Replace any elements inside a that are not plain elements with a regular . This includes any -style custom components.
应该很少会有自定义 Route 的场景出现,这段先暂时不关心。
React Router v6 introduces a Routes component that is kind of like Switch, but a lot more powerful.
v6 版本提供了功能更强大的Routes组件来代替Switch,主要优点如下:
算了...原文的几个优点基本都很少用过。比如示例中的嵌套路由,在实际项目中一般直接写好 config 文件通过 map 渲染,不过Routes不再按顺序匹配路径,而是采用了一种自动匹配最佳路径的方法,这块之后有时间可以阅读下源码或等等大佬们的源码分析贴。
对优点和示例感兴趣的话可以直接查看原文
这算是文章中的第二个破坏性变更:废弃Switch,由Routes代替
