当前位置: 首页 > Web前端 > HTML

React-routerv3tov6探索总结

时间:2023-03-28 01:42:41 HTML

背景目前业务项目中使用的react-router版本为3.x,目前主流使用在5.x以上。本文探讨react-router升级方案目前使用的是react-router3.x版本加4.x5.xAPI变化,配合redux搭配库react-router-redux使用。因为4和5区别不是很大,所以就放在一起说路由不能集中在一个文件里。体现为某个类,如:组件匹配路由,独占路由组件,组件替换`react-router-dom有exact属性,只需要依赖这个组件支持React16,兼容React>=15Route组件路径可以是数组如果没有匹配的路由,也可以通过6.xAPI修改已重命名为,不再需要确切的内容。的新功能更改。再次支持路由嵌套代替和useNavigate代替useHistory。删除了组件新钩子useRoutes而不是react-router-config。尺寸缩减:从20kb到8kb9。增强的路径模式匹配算法。小结从3到4,5之间有很多breakchange,4、5、6之间也有很多breakchange,所以如果当前项目是3,我们打算一次性升级到6,避免中间多次改动upgrade痛点API修改:一般来说唯一的难点在于旧API的语法,调用变了,所以一旦升级,所有地方都得重写。同样是简单的删除,这里也需要修改所有地方,但是这种情况比较少见,删除的API也很少用到API添加:简单添加不影响已有的升级同时需要区分配置API,一般只用一次,比如,只在路由配置页面用到,那我们升级的时候直接修改就可以了。广泛的,比如router.push已经改成了history.pushupgrade现在开始我们的升级redux升级需要升级redux相关的库:react-redux^6.0.0redux-first-history可以删除库:react-router-reduxconnected-react-router只支持v4和v5,这里我们使用redux-first-history,一个更小、更快的替代方案store.js:import{createStore,combineReducers,applyMiddleware}from"redux";import{composeWithDevTools}from"redux-devtools-extension";import{createReduxHistoryContext}from"redux-first-history";import{createBrowserHistory}from'history';//原来的routerMiddleware来自react-router-reduxconst{createReduxHistory,router中间件,routerReducer}=createReduxHistoryContext({history:createBrowserHistory(),//如果需要的话还有其他选项});exportconststore=createStore(combineReducers({router:routerReducer//...reducers//你的reducers!}),composeWithDevTools(applyMiddleware(routerMiddleware)));exportconsthistory=createReduxHistory(store);关于redux-first-history库,如果有依赖redux-devtools,redux-devtools-log-monitor等库,可以不用它这样使用:import{compose,createStore,combineReducers,applyMiddleware}from'redux';importDevToolsfrom'../utils/DevTools';//省略createReduxHistoryContextconstenhancer=compose(applyMiddleware(//...省略logger,routerMiddleware),DevTools.instrument({maxAge:10}));exportconststore=createStore(combineReducers({router:routerReducer//...省略}),enhancer);app.js:import{Provider}from"react-redux";import{HistoryRouteras路由器}来自“redux-first-history/rr6";import{store,history}from"./store";constApp=()=>(//.....);Router新增库:react-router-dom^6.3.0react-router的依赖可以直接去掉,换成上面的redux,我们已经有store,history,Router等重要的属性,那么你只需要控制路由:}>}/>需要注意一点,无论是在组件还是组件中,都不能通过props获取route对象,如果要在中显示组件组件,还需要一个操作:import{Outlet}from"react-router-dom";functionApp(props){//其中Outlet是一个类似于children的占位符return<>//...}之后是hooks中的用法:import{useNavigate}from"react-router-dom";//hooksconstnavigate=useNavigate();//这会将新路由推到导航栈的顶部navigate("/new-route");//这会用导航栈中的新路由替换当前路由改自react-去掉router,放到react-router-dom中,那么怎么修改会更方便呢?关于v6的withRouter,官方不会自带这个组件,因为我们可以通过自由组合它的api:import{useLocation,useNavigate,useParams,}from"react-router-dom";functionwithRouter(Component){functionComponentWithRouterProp(props){letlocation=useLocation();letnavigate=useNavigate();letparams=useParams();return();}returnComponentWithRouterProp;}解决方法是直接全部替换掉??,但是这样也会遇到我们的问题:当这些API,在某个子文件包或者第三方组件被include的时候,就变成了ex更新API非常困难。这也是直接修改的问题。解决方案2目前的思路是使用别名和文件兼容来解决这个问题,比如我在项目中新建一个文件:routerProxy.jsimport*asReactRouterfrom'../node_modules/react-router';import{Link}from'react-router-dom';functionwithRouter(Component){//省略}export*from'../node_modules/react-router';export{Link,withRouter}exportdefaultReactRouter;withwebpackconfiguration:alias:{'react-router':path.resolve(__dirname,'./source/react-router-proxy.js'),}是这样的那个时候参考react-router的东西会去这个文件,这个文件会从node_modules导入,兼容,升级过渡方案3使用babel转换解决:module.exports=function({types:t}){constnamespace=__dirname+'/../node_modules/react-router/es/';constcanReplace=({specifiers})=>{return(specifiers.length>0&&specifiers.every((specifier)=>{return(t.isImportSpecifier(specifier)&&(specifier.imported.name==='Link'||specifier.imported.name==='withRouter'));}));};constreplace=(specifiers)=>{返回说明符。map(({local,imported})=>{if(imported.name==='Link'){returnt.importDeclaration([t.importDefaultSpecifier(local)],t.stringLiteral(`react-router-dom/${imported.name}`),);}returnt.importDeclaration([t.importDefaultSpecifier(local)],t.stringLiteral(`${namespace}${imported.name}`),);});};return{visitor:{ImportDeclaration(path){if(path.node.source.value==='react-router'){if(canReplace(path.node)){//替换path.replaceWithMultiple(replace(path.节点说明符));}}},},};};通过检测import{Link}from'react-router'等语句,替换为react-router-dom仓库解决方案总结解决方案一可以完美解决,但是比较耗费精力。相对来说,我们需要一个平滑升级的方案2和方案3,虽然它们可以解决问题,但是仍然是昙花一现,难以为继。最后,我们还是需要全面更换。总结关于v3的升级问题,v6变化太大,升级到v5可以接受,但是还是要关注最新版本的升级消息,最好去官网查一下,以免遗漏一些细节API对于修改,需要有解决办法。比如当antd升级到大版本的时候,会有一个兼容包需要迁移。当然,本文中的一些方法也可以使用,但必须逐步更换。替换时,使用全局搜索功能。为避免遗漏,注意三方库的兼容性,寻找新版本替代。如果找不到,则需要自己实现。参考https://juejin.cn/post/696624...https://reactrouter.com/docs/...https://github.com/salvoravid...