嵌套路由路径
如果路由路径嵌套深了,并且是写死的,如果有一天想改变一个路径,那不就GG了??
所以,子组件的路由路径前缀应该拿到父组件的path才行!
解决方案
重点在于React没有限制我们,所以,只要我们有办法解决即可!
- match中的url是:真实路径中匹配到路径规则的字符串
- 子组件path的前缀是父组件的match.url即可
- 将所有路由配置抽离出来放到RouteConfig.js,再利用辅助方法导出即可
受保护的页面
公共的授权信息,学了Redux就用Redux处理,目前没学。我们可以直接放在一个对象中
补充: Route组件的render属性
render和children的区别:render是匹配之后才会运行,children无论是否匹配都会运行
<Route path='personal' rende={(values) => {//values是上下文对象,包含history,location,match,staticContext
return 一个类型为React.ReactNode的东西即可
}} />
自定义路由—组件
根据不同的地址,显示不同的组件
所以利用上述玩法,可以实现一个通用的组件,判断如何跳转
ProtectedRoute.js组件
如何从授权页跳回之前的页面呢?
方法一:老方法,利用search的参数returnurl,这样会在地址栏中显示
方法二:新方法,location(hash模式也可以带state)中的state附带returnurl,这样就不会再地址栏中显示了
【扩展】实现Vue路由模式
//RootRouter.js
import React from "react";
import { Route, Switch } from "react-router";
/**
* 根据一个路由配置数组,遍历该数组,得到一组Route组件
*/
export function getRoutes(routes, basePath) {
if (!Array.isArray(routes)) {
return null;
}
const rs = routes.map((rt, i) => {
const { name, children, path, component: Component, ...rest } = rt;
let newPath = `${basePath}${path}`;
newPath.replace(/\/\/+/g, "/");
return (
<Route
key={i}
{...rest}
render={(values) => {
return (
<Component {...values}>{getRoutes(rt.children, newPath)}</Component>
);
}}
/>
);
});
return <Switch>{rs}</Switch>;
}
//使用Route组件,根据不同的路径,渲染顶级页面
export default function RootRouter() {
return <>{getRoutes(routeConfig)}</>;
}
//BetterLink.js
import React from "react";
import { Link } from "react-router-dom";
export default function BetterLink(props) {
const { to, ...rest } = props;
if (to.name && typeof to !== "string") {
to.pathname = getPathFromName(to.name, '/', routeConfig);
if(to.pathname === undefined){
throw new Error(`name属性值${to.name}无效!`)
}
}
return <Link {...rest} to={to} />
}
/**
根据name的值,查找对应的path,没有考虑有params的情况
如果有,会比较复杂,需要用到path-to-regexp库
*/
function getPathFromName(name, baseUrl, routesArr) {
for (const item of routesArr) {
let newPath = `${baseUrl}${item.path}`;
newPath.replace(/\/\/+/g, "/");
if (item.name === name) {
return baseUrl + item.path;
} else {
if (Array.isArray(item.children)) {
const path = getPathFromName(name, newPath, item.children);
if (path !== undefined) {
return path;
}
}
}
}
}