弗曼学习大法好
记录一下之前写的React可配置路由
主要实现的是通过config文件生成路由,
功能应该和react-router-config差不多(还没看,
不过自己写下踩踩坑也许会有收获

CRA创建app (秉持着学习的心态我装了ts,react-router-dom@6.0
从0开始看看会遇到什么坑

npm install -D react-router-dom
npm install -D -S @types/react-router-dom

新建
src/router/routerConfig.ts //路由配置
src/type/type.ts //主要是为了统一导出interface
src/type/RouterType.ts //路由类型

// RouterType.ts
export interface RouterMenuType {title: string
}export interface RouterType {path: string, //路径component: string, //组件所在位置,以src/pages为起点menu?: RouterMenuType, //如果不为空则显示在菜单上icon?: string,//子路由(这个部分其实可以直接在外层新建,但是考虑到后面想要实现面包屑,所以写在这里routes?: Array<RouterType>, //下一层路由childrens?: Array<RouterType> //嵌套路由
}

我们的目的是通过配置这一个RouterType类型的json文件,完成路由和嵌套路由的配置。
现在我们先写一个简单的配置json。
在此之前我配置了一下alias,可以参考下这个链接
https://www.jianshu.com/p/6f8a98a9f2e2

import { RouterType } from "@/types/types";export const authRouterConfig: Array<RouterType> =[{path: '/home',component: 'Home',menu: { title: 'Home'},icon: 'Home',},{path: '/user',component: 'User',menu: { title: 'User'},icon: 'User',routes:[{path: '/edit/:id', component: 'Edit', routes: [{path: '/test/:id',component: 'Test',},]}],childrens: [{path: '/detail/:id',component: 'Detail',},],}];

新建文件
src/layout/index.tsx
src/layout/MainPane.tsx // 内容主页面
src/layout/MenuPane.tsx // 侧边栏
src/router/routerTool.ts // 工具方法

那首先我们需要格式化一下我们的配置文件
在routerTool中创建方法

//获取符合条件的Router(未来可能做鉴权
export const getAuthRoutes = (routers: Array<RouterType>, fatherRouter: RouterType = { path: "", component: "" }) => {return routers.reduce((res: Array<RouterType>, route: RouterType) => {const newRoute: RouterType = {...route,path: fatherRouter.path + route.path,component: (isEmpty(fatherRouter.component) ? '' : fatherRouter.component + '/') + route.component,}if (!isUndefined(route.childrens)) {newRoute.childrens = getAuthRoutes(route.childrens, newRoute)}if (!isUndefined(route.routes)) res.push(...getAuthRoutes(route.routes, newRoute));res.push(newRoute);return res;}, [])
}

这个方法传入routers,还有fatherRouter,
做递归拼接children的路径以及component路径,
并且将router内的routes拼接path并拆分到外部,
格式化之后的数据是这样子

[{"path": "/home","component": "Home","menu": {"title": "Home"},"icon": "Home"
}, {"path": "/user/edit/:id/test/:id","component": "User/Edit/Test"
}, {"path": "/user/edit/:id","component": "User/Edit","routes": [{"path": "/test/:id","component": "Test"}]
}, {"path": "/user","component": "User","menu": {"title": "User"},"icon": "User","routes": [{"path": "/edit/:id","component": "Edit","routes": [{"path": "/test/:id","component": "Test"}]}],"childrens": [{"path": "/user/detail/:id","component": "User/Detail"}]
}]

下一步是通过这个格式化之后的数组渲染menu和main

MenuPane.tsx
import { FC } from 'react';
import { NavLink } from 'react-router-dom';
import { RouterType } from '@/types/RouterType';interface Iprops {routes: RouterType[]
}const LeftPane: FC<Iprops> = (props: Iprops) => {const { routes } = props;return (<div><ul className="list">{routes.filter((item) => typeof item.menu != "undefined").map((item) => (<li key={item.path}><NavLinkto={item.path}><div><b>{item.menu?.title}</b></div></NavLink></li>))}</ul></div>);
}export default LeftPane;

Menu通过判断menu是否存在来决定是否显示菜单项,
而Main的话我们需要再新建两个component
src/components/router/RouterComponent.tsx
src/components/router/SwitchRouter.tsx

import React, { FC, lazy, useEffect } from "react";
import { RouterType } from "@/types/RouterType";interface Iprops {route: RouterType
}const RouterComponent: FC<Iprops> = (props) => {console.log(props);const { route } = props;const DynamicComponent = lazy(() => import(`@/pages/${route.component}`));return <><React.Suspense fallback={'loading...'}><DynamicComponent {...props} childrenRoutes={route.childrens}/></React.Suspense></>
}export default RouterComponent;

RouterComponent接受route,使用React.lazy懒加载引入组件,
我们的component变量中存储的只是字符串,拼接过后成为了一条文件夹都路径,所以配置文件和文件目录需要对应上

import React, { FC } from 'react';
import { Route, Navigate, Routes } from 'react-router-dom';
import { isUndefined, isArray, isEmpty } from 'lodash';
import { RouterType } from '@/types/types';
import RouterComponent from './RouterComponent';interface Iprops {routes: Array<RouterType>
}const renderRouter = (routes: Array<RouterType>) => {return <>{isArray(routes) && routes.map((route: RouterType) => (<Routekey={route.path}path={route.path}element={<RouterComponent route={route}/>}>{ route.childrens && renderRouter(route.childrens)}</Route>))}</>
}const SwitchRouter = ({routes}: Iprops) => {return (<Routes>{renderRouter(routes)}{!isEmpty(routes) && <Routepath="*"element={<Navigate to={routes[0].path}></Navigate>}/>}</Routes>)
}export default SwitchRouter;

SwitchRouter中,遍历渲染route,在判断有childrens的时候嵌套渲染childrens
(此处为react-router-dom@6.0以上版本的写法,在旧版本的话,应该在子路由都父组件中调用renderRouter(…)渲染嵌套路由

SwitchRouter组件渲染路由,并且在找不到match路径的时候,从当前路由中找到第一个路由跳转
(用于替换旧版本都)

(SwitchRouter部分,Routes是否在这里使用还有待商榷,因为这里还没有404界面都配置,而且不一定所有路由都会在MainPane中,例如登陆界面,或者其他不需要登陆都界面之类的)

最后我们先简单写一层MainPane,然后在Layout中使用

import React from 'react';interface Iprops {children: React.ReactNode | React.ReactChild[],
}const MainPane = (props: Iprops) => {const {children,} = props;return (<div className="main-pane">{children}</div>);
}export default MainPane;
import React, { FC } from "react";
import { BrowserRouter as Router } from "react-router-dom";
import { authRouterConfig } from "@/router/routerConfig";import SwitchRouter from "@/components/Router/SwitchRouter";
import MainPane from "./MainPane";
import MenuPane from "./MenuPane";
import { getAuthRoutes } from "@/router/routerTool";const Index: FC = () => {const authRoutes = getAuthRoutes(authRouterConfig);return <Router><div className="layout"><div><div><MenuPane routes={authRoutes} /></div><div><MainPane><SwitchRouter routes={authRoutes}></SwitchRouter></MainPane></div></div></div></Router>}export default Index;

在Layout调用后,我们就可以编写简单都组件了,
Home 和 User

这里使用user做例子
src/pages/User/index.tsx
src/pages/User/Detail.tsx
src/pages/User/Edit
src/pages/User/Edit/index.tsx
src/pages/User/Edit/Test.tsx

index.tsxconst { childrenRoutes } = props;console.log('childrensRoutes', childrenRoutes);let navigate = useNavigate();return <div><button onClick={() => navigate({pathname: '/user/detail/1'})}>Detaillll</button><br/><br/><button onClick={() => navigate({pathname: '/user/edit/1'})}>Edit</button><br/><br/><button onClick={() => navigate({pathname: '/user/edit/1/test/1'})}>Edit/Test</button><br/><br/><Outlet /></div>
};

useNavigat用来代替旧版本都History
为6.0的新API,刚才我们在渲染的时候,将/user/detail放入了childrens中,
所以在这里Outlet就是detail的出口,detail组件会显示在这里

剩余的组件也需要按照我们router-config.json的路径创建

如此一个最简单的可配置,支持懒加载的路由就可以运行了。

下一步的话,可能会结合redux和这个可配置路由完成面包屑的导航。

写一个最简单的React可配置路由(react-router相关推荐

  1. Java入门知识,写一个最简单java程序

    本文目录 一.Java语言的简介 二.写一个最简单Java程序 1.Notepad配置 2.最简单的Java程序 3.代码分析 4.编译与编译常见错误 5.执行java程序 一.Java语言的简介 0 ...

  2. 如何写一个完整的django网站:配置环境啥的不讲(python+mysql+html相关) 肆

    虽然好像到现在为止只有几个人看了,但是心塞的作者还是给大家放一下网站的目录伐, 其中两个文件夹中可以忽略,存放css和js样式的,但是实践证明必须导入外部文件中的内容,额,js和css存放在图片2所示 ...

  3. 用JAVA写一个最简单的飞翔的小鸟

    如果你想写一个最简单的飞翔的小鸟的 Java 程序,可以先了解 Java 的图形绘制功能.Java 提供了一个叫做 Graphics 的图形绘制类,可以用来绘制图形.填充颜色.画线等. 你可以通过创建 ...

  4. 利用taichi写一个最简单的SPH(光滑粒子动力学)

    简介 参考doyub Kim那本<Fluid Engine Development>写一个最简单的弱可压SPH. 目前有BUG, 粒子太散了 效果展示 CSDN有图片大小限制,大概就这样 ...

  5. 如何用初级的JavaWeb知识写一个较简单的网站(一)

    本人JavaWeb初学者,这是学校一门课程的期末作业,之前已经写了不少了,但是由于一点误操作,导致项目有点崩盘,加上心态不是很好,所以把整个项目全部删除重做,这里记录一下我写整个项目的全过程. 环境是 ...

  6. 自己写一个最简单的bootloader_jz2440

    写在前面: 我的博客已迁移至自建服务器:博客传送门,CSDN博客暂时停止,如有机器学习方面的兴趣,欢迎来看一看. 此外目前我在gitHub上准备一些李航的<统计学习方法>的实现算法,目标将 ...

  7. 安装汇编环境,写一个最简单的窗口程序

    用汇编写一个窗口程序 1.安装汇编所需的环境 1.下载masm32 下载地址 可以安装到D:\masm32目录下 2.配置环境变量 include = D:\masm32\include lib = ...

  8. cmd写java程序_用cmd写一个最简单的Java程序

    一,准备: 1.确保电脑中装有eclipse软件并且确保配置好环境变量 (1)环境变量配置方法: 特别提示:jdk和eclipse保存的路径不能有中文字符 1.打开我的电脑--属性--高级--环境变量 ...

  9. python写一个很简单的Atm机系统,使用pickle模块和json模块来保存数据

    我做的是一个很简单的Atm系统,很多都没约束条件 目的: 用面向对象思维来处理 运用文件的读写 文件的读写用pickle模块和json模块来处理 pickle模块: pickle模块处理数据功能很强大 ...

  10. Unity自学第一天, 新手小白进!写一个最简单的脚本让方块旋转起来

    Unity自学入坑第一天 今天开始自学unity,如何让场景中的基本方块开始旋转起来,一个非常简单的小sample,作为入门,本人纯纯新手小白,之后会继续更新所有自学记录 在场景中添加一个方块,左边空 ...

最新文章

  1. .vimrc文件中的leader是什么?
  2. WTM系列视频教程:View和Taghelper
  3. CTF工具-gdb简介
  4. Microsoft SQL Server 2005 提供了一些工具来监控数据库
  5. Linux系统编程2:基础篇之详解Linux中的权限问题
  6. thinkjs——两表联查
  7. 保险科技服务商豆包网完成9500万新一轮融资,博将资本领投
  8. php mysql登陆页面完整代码_PHP实现用户登录的案例代码
  9. Machine Learning(机械学习)
  10. 75. 颜色分类(图解)
  11. 百度竞价推广应如何做好!
  12. 阿里技术专家楚衡:架构制图的工具与方法论
  13. oracle io错误的是什么意思,磁盘IO错误 导致数据库故障一则
  14. 【Kafka】(二十四)轻量级流计算 Kafka Streams 实践总结
  15. input.validity
  16. 马士兵—JVM—内存溢出—2.arthas阿里线上Java诊断工具
  17. 线程开的越多就越好吗|趣谈线程池
  18. 五常大米引入蚂蚁金服区块链,从大米“出生”就开始“验明正身”
  19. 文献阅读笔记(2022.11.14)
  20. 0005 键盘打字如何练成像黑客一样的飞速

热门文章

  1. 谷歌浏览器怎么长截图怎么截_Google浏览器如何截取网页长图 - 里维斯社
  2. H5混合APP开发框架
  3. 计算机二级基础知识题库贴吧,考计算机二级用未来教育的题库会出原题吗
  4. CSS · 单行、多行文本溢出显示省略号
  5. 贴片钽电容封装及规格参数资料
  6. MVC/POJO/POJI/DAO/DTO/VO
  7. ip 域名 端口了解
  8. 2022腾讯云学生云服务器申请攻略(25岁以下免学生认证)
  9. PAT题集2019.6.22排名变动
  10. 201671030119 词频统计软件项目报告