我的博客地址
正式地址
测试地址
前端源码
后端源码
文章目录
- 项目及其技术栈介绍
- 前端: 项目初始化
- 前端: 使用Sass和Antd
- 前端: 开发体验优化
- 前端: 搭建路由和状态管理
- 前端: 支持Axios
- 前端: 打包与环境变量设置
- 前端: 团队代码规范
- 后端: 项目初始化和使用Koa相关
- 后端: 使用TypeORM和MySQL
- 部署: 使用nginx部署前端项目
- 部署: 后端部署
- 部署: 使用jenkins自动化部署
前言
该篇博客介绍如何使用react-router4+搭建前端路由,并使用最新的suspense和lazy构建路由的按需加载。同时介绍状态管理的搭建,其中在状态管理搭建中,会尝试使用最新的useReducer
+context
来搭建前端的状态管理,以及他与TypeScript之间的配合。
- React Router4+,suspense,lazy
- useReducer + context
前端路由搭建
安装react-router
首先我们需要安装react-router
以及他的类型文件
npm i -S react-router-dom
npm i -D @types/react-router-dom
在这里说一下react-router
和react-router-dom
之间的区别:
react-router
是react-router-dom
的核心代码,提供理由的核心api,例如Router、Route、Switch
等,而react-router-dom
提供了BrowserRouter,Link
等api,react-router-dom
里面包含了react-router
,所以一般只需要安装react-router-dom
-
编写路由页面
然后我们在src/containers/views
中编写两个路由页面PageA
和PageB
-
接着我们还是在
src/containers/views
中新建App
组件,并在App组件下新建routerMap.tsx
文件用作存放路由表。
在routerMap
文件中,我们引入lazy
方法,并通过import()
引入PageA
和PageB
,然后通过统统放到一个数组中,将这个数组导出去:
-
我们去到
App/index.tsx
中,从react-router-dom
中导入BrowserRouter, Route和Switch
,以及从React中导入Suspense
组件,然后编写路由文件,并将其用Suspense
包裹起来,使用了lazy方法导入的组件必须用Suspense
包裹,否则不能加载出来并报错:
-
在这里需要注意的是,如果使用的是
BrowserRouter
,需要在webpack中加上devServer配置,并打开historyApiFallback
,原因是当跳转到page-b
页面的时候,他会试图寻找page-b.html
,但我们是单页应用,所以没有这个文件,从而出现找不到的情况,而historyApiFallback
会在找不到页面的情况下跳转回index.html
,避免直接出现找不到的情况:
-
最后我们回到页面查看跳转情况:
路径为/
的时候加载PageA
:
当路径切换为/page-b
的时候,则加载PageB
:
这时候我们的前端路由就搭建好了,并且可以进行动态加载 -
使用
withRouter
方法进行路由跳转
去到PageA
页面添加如下代码:
这时候点击跳转B按钮的时候就能够跳转到/page-b
路径了:
状态管理搭建
在React技术栈中我们通常使用Mobx
,Redux
进行前端状态管理,但在本项目中未采用这两个库,而是使用了useReducer + context
的方式来进行搭建,而本文中则使用一个加减计数器的方式来展示如何搭建和使用useReducer + context
状态管理
进行这一步之前首先需要知道如何使用useContext、createContext以及useReducer
-
首先我们在
src
文件夹下新建两个文件夹store
和components
,其中store
用于存储共用状态和配置,components
用于存放组件。
-
然后我们在
store
文件夹中新建index.tsx
文件和count
文件夹,在count
文件夹中新建index.tsx
、reducer.ts
以及types.d.ts
文件:
-
其中
index.tsx
文件用于存放Provider
和初始状态,如下图:
-
然后在
reducer.ts
中,我们开始编写reducer
:
编写完成在index.tsx
中导入:
-
解决类型报错问题
这时候你会发现reducer和index.tsx中都存在很多报错,这是因为没有添加类型导致ts认为他们是any类型,所以我们为他们添加类型文件。
我们去到之前新建的types.d.ts
文件中,定义好state的接口和action的类型,为了避免今后store变得原来越大,我们使用命名空间来避免命名冲突:
之后到reducer.ts
将类型补充上去:
而index.tsx
中props
的报错则可以使用React自带的ComponentType
类型将Provider
定义为组件类型以解决:
-
定义Context的类型
另外有些小伙伴可能会有如下ts错误:
这是因为我们在createContext
中传入的参数为null
导致的。
要解决这个问题首先我们去到src/types
文件夹中新增context.d.ts
文件,接着定义Context的类型,注意因为之前在Context的value
中我们放入的是state
和dispatch
,所以这两个都需要进行定义,而state和dispatch每个store可能都不一样,所以需要用到泛型:
之后到index.tsx
中进行使用,注意这里我们从react中导入了Dispatch
类型:
最后我们到tsconfig.json
中将strictNullChecks
的属性设置为false:
-
最后我们回到
store/index.tsx
文件中,导入所有的Provider
和useXXXStore
,然后组成一个数组,通过一个总的Provider
进行导出:
然后到src/index.tsx
中导入这个总的Provider
,并使用它包裹<App />
组件
-
验证成果
验证成果之前我们需要先将store和components的路径别名分别添加进webpack和tsconfig中去,不动怎么添加的看我上一篇文章:
我们到之前新建的components
文件夹中新建两个组件CountOperation
和ShowCount
:
然后在里面将
useTestStore
方法从store引入,这个方法执行后可以得到state
和dispatch
并且这些都是带有类型提示的,说明我们的ts和
useReducer + context
结合得非常棒了:最后把这两个组件在PageA
页面中引入进行成果验证:
查看结果:
这样我们的useReducer + context
的状态管理方案就完成了。
难点我估计在于对Context的类型编写,因为这一块会用到嵌套的泛型,而泛型在TypeScript中是一个难点,但这个难点是必须攻克的: