【山竹记账前端-react】2.React Router 6 实践
大纲链接 §
[toc]
1. 安装、初始化路由 ⇧
安装的是 react-router-dom@6.30.6 ⇧
react@18.3.1+react-router-dom@6.30.6注:
react-router@7+ ~ react-router@8+有重大破坏性变更,更适配react@19+1pnpm add react-router-dom@6.30.6
package.json
|
|
引入到
main.tsx,初始化路由
|
|
参考
2. 404路由 errorElement ⇧
https://reactrouter.com.cn/en/main/start/tutorial#handling-not-found-errors处理未找到错误
- 和预想的
404页面不同,React Router当做错误处理 在路由表中添加属性
errorElement1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21import { createBrowserRouter, Link, } from "react-router-dom"; const router = createBrowserRouter([ { path: "/", element: ( <div> <h1>Hello World</h1> <Link to="about">About Us</Link> </div> ), errorElement: <>访问的页面不存在</>, }, { path: "about", element: <div>About</div>, }, ])
可以创建一个单独的
ErrorPage.tsx
|
|
引入到
src/main.tsx的errorElement中
|
|
3. 嵌套路由 children ⇧
在
routes中
- 添加属性
children,添加子路由 添加属性
<Outlet />,占位1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26import { ErrorPage } from '@/components/ErrorPage' import { Link } from 'react-router-dom' export const routes = [ { path: '/', element: ( <div> <h1>Hello World</h1> <Link to="about"> About Us </Link> <Outlet /> </div> ), errorElement: (<ErrorPage />), children: [ {index: true, element: (<div>请选择</div>)}, {path: '1',element: <div>1</div>,}, {path: '2',element: <div>2</div>,}, {path: '3',element: <div>3</div>,}, ], }, { path: 'about', element: <div>About </div>, }, ]访问路由
http://localhost:5173/1但却跳转到了根路由React Router并不知道在哪里显示这个节点元素- 需要添加个类似插槽的标签
<Outlet /> - 子路由元素才会显示在
<Outlet />占位处
此时如果只是访问根路径,就没有显示子路由元素了,即未匹配子路由
- 可以添加默认子路由
{index: true, element: (<div>请选择</div>)}为显示在<Outlet />处的默认内容 - 可以直接把这个子路由就当做此路径的内容
- 其他子路由不写
index属性的,默认为false
- 可以添加默认子路由
如果父路径
element没有其他结构,只有一个<Outlet />占位,那么element: (<Outlet />)可以直接省略不写,效果一样outlet译为 出口类似
Vue Router的<RouterView />1 2 3 4 5 6 7 8 9 10 11 12 13 14export const routes = [ {path: '/3', element: (<div>先匹配的3</div>)}, { path: '/', // element: <Outlet />, // 可省略 children: [ {index: true, element: (<div>请选择</div>)}, {path: '1',element: <div>1</div>,}, {path: '2',element: <div>2</div>,}, {path: '3',element: <div>3</div>,}, ], }, {path: '/3', element: (<div>后匹配的3</div>)}, ]
此时,如果单独路由
/3的路由,和原来路由中的子路由,是该如何匹配?
- 写在前面的先会匹配到,后面的写的就忽略,不会再匹配
4. 重定向:useNavigate ⇧
welcome/1,2,3,4的最佳实践,改造路由表
|
|
重命名
errorElement组件<ErrorPage />为<RedirectToWelcome1 />,并修改为强行跳转重定向到/welcome/1
|
|
- 使用
useNavigate获取导航函数nav nav必须在useEffect中使用- 即可以在
errorElement中做重定向路由 目前就可以实现在子路由
/welcome中任意不匹配的路由都重定向到/welcome/11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23import { RedirectToWelcome1 } from '@/components/RedirectToWelcome1' import { Outlet } from 'react-router-dom' export const routes = [ { path: '/', errorElement: (<RedirectToWelcome1 />), children: [ { index: true, element: (<div>root</div>) }, { path: 'welcome', children: [ { index: true, element: <div>welcome root</div> }, { path: '1', element: <div>welcome 1</div> }, { path: '2', element: <div>welcome 2</div> }, { path: '3', element: <div>welcome 3</div> }, { path: '4', element: <div>welcome 4</div> }, ], }, ], }, ]
5. 路由页面过渡动画:react-spring 入门 ⇧
实现点击跳转 <NavLink to="" /> ⇧
|
|
react-spring ⇧
由于使用
react@18.3.1,按照官网区分@19±不同版本,需要安装pnpm add @react-spring/web@9
|
|
添加
@/components/Demo.tsx
|
|
<animated.div style={...} />添加部分默认样式useSpring传参为一个函数() => ({from: { x: 0 }, to: { x: 100 },})- 解构出
[springs, api] springs添加到style中,动画配置属性api控制操作api.start({ from: {x: 0}, to: {x: 100} })
- 解构出
引入到
routes.tsx查看效果
|
|
- 以上
Demo只实现了对于一个元素的动画 - 路由需要实现两个页面之间的过渡
- 删掉
Demo
参考
重构代码:拆分路由 ⇧
单页应用只有一个
router,提取路由表到文件@/route/routes.tsx
|
|
重构新建
@/route/router.tsx
|
|
重构
@/main.tsx
|
|
@/main.tsx渲染根组件- 根组件引入
<RouterProvider router={router} />
- 根组件引入
重构代码:抽取组件到 @/layouts/ @/pages/ ⇧
|
|
提取四个页面组件
@/pages/Welcome1.tsx
|
|
重构
@/route/routes.tsx
Ctrl + Shift + J合并成一行JoinLine1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28import { NavLink } from 'react-router-dom' import { RedirectToWelcome1 } from '@/components/RedirectToWelcome1' import { MainLayout } from '@/components/layouts/MainLayout' import { WelcomeMainLayout } from '@/components/layouts/WelcomeMainLayout' import { Welcome1 } from '@/pages/Welcome1' import { Welcome2 } from '@/pages/Welcome2' import { Welcome3 } from '@/pages/Welcome3' import { Welcome4 } from '@/pages/Welcome4' export const routes = [ { path: '/', element: <MainLayout />, errorElement: (<RedirectToWelcome1 />), children: [ { path: 'welcome', element: <WelcomeMainLayout />, children: [ { path: '1', element: (<Welcome1 />) }, { path: '2', element: (<Welcome2 />) }, { path: '3', element: (<Welcome3 />) }, { path: '4', element: (<Welcome4 />) }, ], }, ], }, ]
重构代码:目录结构变化 ⇧
目前目录结构变得清爽
@/components/放通用组件@/layouts/放布局组件@/pages/放页面组件@/router/放路由相关
在
VSCode中重构
- 例如重命名、移动组件,对应路径自动改变,需要装
Auto Import之类的插件 - 如果错误
typescript会立马报错 - 分目录
参考文章
- 初始代码:https://github.com/FrankFang/6KQwMfYK
- 最终代码:https://github.com/FrankFang/J2vObTEF
- 提交历史:https://github.com/FrankFang/J2vObTEF/commits/master
相关文章
- reactrouter@8+ 英文官方文档
- reactrouter@7+ 中文非官方文档
- react-router 的 v6+ 版本和 v7+、v8+ 版本有什么区别,是否有重大的 breakpoint。最核心的区别是什么?
- React Router v6+ 主分支文档 for React@18
- exhaustive-deps
- Why The ESLint Rule “react-hooks/exhaustive-deps” Requires All Dependencies in useEffect’s Dependency Array?
- react-spring 官网
- 作者: Joel
- 文章链接:
- 版权声明
- 非自由转载-非商用-非衍生-保持署名