如今 react-router 已经升级到v5.0版本,v4.0版本做了较大的改革,代码中依然使用v3.0版本的写法,于是准备整改为v4.0以上版本,遇到了很多坑,于是做个笔记。
首先,对比一下 v3.0 和 v4.0 版本:
- v4.0提供了react-router-dom:是基于react-router,加入了在浏览器运行环境下的一些功能,例如:Link 、NavLink、BrowserRouter和HashRouter组件
- v4.0提供了react-router-config:一个帮助我们配置静态路由的小助手;可以拆分统一管理路由配置,这里很像Vue的写法
- v4.0中BrowserRouter 和 HashRouter 取代v3.0中的 <Router history={browserHistory} 和 history={hashHistory} />
- v4.0 中废弃了 < IndexRoute > ,但可以使用 < Route exact > 来达到同样的效果,新增的 < Switch > 标签,用于互斥路由
- v4.0版本中路由的本质变成了React组件,也就是自定义标签。所以你可以像使用组件一样是用路由。那么嵌套路由无非就是组件嵌套的写法
代码对比:
index.js
// v3.0
import { Router, Route, hashHistory, IndexRedirect } from 'react-router'
<Router history={hashHistory}>
<Route path={'/'} components={App}>
<IndexRedirect to="/Index/Home" /> // 重定向路由
<Route path={'/Index'} component={Index}>
<IndexRedirect to="/Index/Home" /> // 子路由重定向
<Route path={'/Index/Home'} components={Home}/>
<Route path={'/Index/Classify'} components={Classify}/>
</Route>
<Route path={'/Login'} components={Login}/>
<Route path={'/404'} component={NotFound}/>
</Route>
</Router>
// v4.0
import { HashRouter, Route, Switch, Redirect } from 'react-router-dom';
<HashRouter>
<Switch>
<App> // 这里使用 <Route path={'/'} exact component={App} /> 会报警告
<Route path={'/Index'} component={Index}>
<Redirect to='/Index/Home' /> // 访问 /Index及下级失效路径会重定向到 /Index/Home
<Route exact path={'/Index/Home'} components={Home}/>
<Route path={'/Index/Classify'} components={Classify}/>
</Route>
<Route path={'/Login'} components={Login}/>
<Route path={'/404'} component={NotFound}/>
<Redirect from='/' to='/Index/Home' /> // 访问根路径重定向到 /Index/Home
</App>
</Switch>
</HashRouter>
接下来,我们利用v4.0 版本高阶函数拆分路由统一配置(类似vue写法):
routes.js:
let routes = [
{
path: '/Index',
component: Index,
exact:true
},
{
path: '/Home',
component: Home,
exact:false
},
{
path: '/Login',
component: Login,
exact:false
},
]
export default routes
index.js:
import routes from './router/routes'
import { HashRouter, Route, Switch, Redirect } from "react-router-dom";
import App from "./App";
ReactDOM.render(
<HashRouter>
<App> // 这里使用 <Route path={'/'} exact component={App} /> 会报警告
<Switch> // 利用map遍历每一项,这里因为是组件,key要注意
{
routes.map((route,index) => (
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.component}
/>
))
}
<Redirect from='/' to='/Index'></Redirect> // 根路径重定向到 /Index
</Switch>
</App>
</HashRouter>,
document.getElementById('root')
);
实现简单的路由拆分管理,这里也可以利用react-router-config插件内置方法renderRoutes实现,其源码也是基于如下方式;
接下来,我们解决处理组件嵌套的情况:
routes.js:
let routes = [
{
path: '/Index',
component: Index,
exact:true
},
{
path: '/Home',
component:Home,
children:[
{
path:'/Home/ShoppingCart',
component:ShoppingCart,
exact:true
},
{
path:'/Home/Classify',
component:Classify,
exact:false
},
]
},
{
path: '/Login',
component: Login,
exact:false
},
]
export default routes
index.js:
import routes from './router/routes'
import { HashRouter, Route, Switch, Redirect } from "react-router-dom";
import App from "./App";
ReactDOM.render(
<HashRouter>
<App> // 这里使用 <Route path={'/'} exact component={App} /> 会报警告
<Switch> // 利用map遍历每一项,这里因为是组件,key要注意
{ // 利用render 渲染子路由
routes.map((route,index) => (
<Route
key={index}
path={route.path}
exact={route.exact}
render={(props) => { // 利用render 方法处理
if (route.children){
return (
<div>
<route.component props={props}></route.component>
<Switch>
{
route.children.map((child,i) => (
<Route
key={i}
path={child.path}
exact={child.exact}
component={child.component}
/>
))
}
<Redirect to={route.children[0].path}></Redirect> // 子路由找不到,重定向到第一个子路由
</Switch>
</div>
)
}else {
return (
<route.component props={props}></route.component>
)
}
}}
/>
))
}
<Redirect from='/' to='/Index'></Redirect> // 根路径重定向到 /Index
</Switch>
</App>
</HashRouter>,
document.getElementById('root')
);
基本实现配置,简单来说,利用map方法遍历Route对象,子路由也是如此,这里要注意子组件的props为空情况,这里利用Route的props传递,也可以使用withRouter()方法解决