【山竹记账前端-react】9.搭建 Mock、封装 Axios、使用 SWR
大纲链接 §
[toc]
实现首页,需要分以下几种情况
- 如果没有登录:可选显示首页,重定向到登录
- 如果登录但没有记账:展示首页
- 如果登录且记过账:记账列表页面
为什么要 Mock
- 后台接口还没完成,但前端要用到接口数据
- 我想篡改后台接口的结果来测试
1. 使用 swr 发送关联请求 ⇧
实现 Mock
- 需要篡改接口的返回值,包括状态码和消息体
- 需要mock
/api/v1/me - 需要mock
/api/v1/items - 判断记账账目数据长度大于零,需要跳转
- 在页面挂载之后才发请求,使用
useEffect模拟,多个前后依赖条件的接口会嵌套 使用
useSWR解决请求嵌套问题,内部会使用useEffect,可以直接替代useEffect1 2 3 4 5 6 7 8 9 10// ... export const Home: React.FC = () => { const {data: meData, error: meError} = useSWR('/api/v1/me', (path) => { return axios.get(`https://xx.xxx.xxx.xx:xxxx${path}`) }) const {data: itemsData, error: itemsError} = useSWR(data1 ? '/api/v1/items' : null, (path) => { return axios.get(`https://xx.xxx.xxx.xx:xxxx${path}`) }) // return ... }前后依赖的关联请求可以使用技巧:
const {data, error} = useSWR(data1 ? '/api/v1/items' : null, () => {})判断前一个数据是否为空来设置请求路径
data1 ? '/api/v1/items' : null当第一个请求的
data1还未成功时,值为空,则第二个请求路径为空,不发请求等第一个请求数据有内容后,UI 重新渲染,才会去请求第二个 api
2. 使用第三方 Mock 工具 ⇧
apiFoxapiPost- 第三方商业服务可能面临收费、宕机或者供应链投毒等情况
参考
3. 自己搭建 Mock 服务器 ⇧
安装
pnpm add vite-plugin-mock@3.0.2 -D- 无需另外安装
mockjs
配置
vite.config.ts
|
|
- 仅在开发环境使用,判断:
enable: command === 'serve' - 也可以配置在
.env.production和.env.development中配置 - 注意配置路径
mockPath: './src/mock',默认在src同级目录
添加文件
src/mock/test.ts
|
|
重启
vite服务,利用vite本身服务器的功能模拟接口数据
get请求直接访问浏览器地址http://localhost:5173/api/v1/me
再添加
/api/v1/items接口模拟数据
|
|
目前已经做到
- 在本地
5173端口模拟api响应数据
在页面中模拟访问当前地址接口
@/pages/Home.tsx
|
|
4. 封装 Axios ⇧
使用 vite 配置区分开发与生产环境 ⇧
需要根据环境切换地址
pnpm dev当处于开发环境访问地址前缀/api/v1/xxpnpm build当处于生产环境访问地址前缀为真实服务器地址https://xx.xxx.xxx.xx:x0x0/api/v1/xx
配置
vite.config.ts
|
|
- 添加配置项
define: { __IS_DEV__: command === 'serve' },表示是否在开发环境,否则表示在部署生产环境 define配置的属性会被添加全局变量中,即可访问globalThis.IS_DEV或window.__IS_DEV__
参考
封装请求库 ⇧
解耦页面请求,最小知识原则
- 使用时,不需要知道是在使用
axios库 - 封装成自己使用的api,即使请求库换成原生
fetch或者其他请求库,对使用者无感 - 目前仅提供四种方法
get|post|patch|delete
@/lib/request.ts
|
|
ts不认识__IS_DEV__,添加全局环境类型声明@/vite-env.d.ts
|
|
参考
- 是否可以在 global.d.ts 中声明 export const IS_DEV: boolean 而不赋值
- vite define
- 重新设计 define 和 import.meta.env.* 的替换策略
- 在配置中使用环境变量
测试开发环境
- 运行
pnpm dev - 查看接口是否直接访问当前网址
http://localhost:5173/api/v1/xxx - 打开浏览器网络面板查看
Request URL
测试生产环境
- 运行
pnpm build - 搜索产物是否包含网址
http://localhost:5173/api/v1/xxx
更多 axios 配置 ⇧
封装单独的 axios 实例
@/lib/request/axiosInstances.ts
|
|
重构
@/lib/request/request.ts
|
|
参考
5. 设置远程资源的类型 ⇧
全局类型 ⇧
即返回响应数据的类型,本项目基本包括以下几种
- 单数类型
resource: {/* 数据 */} - 复数类型
resources: [{/* 数据1 */}, {/* 数据2 */}, ...], pager: {page: number, per_page: number, count: number}
声明到全局类型文件
@/global.d.ts
|
|
表示请求方法中获取信息的类型 ⇧
修改
@/pages/Home.tsx
|
|
此时原来声明的
request中的各个请求方法为声明类型而报错@/lib/request/request.ts
|
|
- 注意
request.ts不能命名为request.tsx,因为其中的泛型类型声明<T>括号和TSX语法冲突 目前将鼠标移到
meData上可以看到返回数据的类型提示1const meData: AxiosResponse<Resource<User>, any, {}, any> | undefined
进一步解构明确
meData数据@/pages/Home.tsx
|
|
- 更简洁:
useSWR('/api/v1/me', async path => (await request.get<Resource<User>>(path))?.data) - 更简洁:
useSWR(meData ? '/api/v1/items' : null, async path => (await request.get<Resources<Item>>(path))?.data)
完善 Mock 数据类型 ⇧
@/global.d.ts
|
|
@/mock/test.ts
|
|
- 可以添加延时
timeout: 2000
完善跳转逻辑 ⇧
@/pages/Home.tsx
|
|
- 由于
if (itemsData?.resources?.length > 0) { return <Navigate to="/items" /> }中可能为类型undefined,不能和 0 比较,ts报错 - 取巧可改写为
if (itemsData?.resources?.[0]) { return <Navigate to="/items" /> }表示用户是否记过账
新建/items空白组建占位 ⇧
@/route/routes.tsx
|
|
后续再完善加载中页面和完成记账页面
6. 封装 useTitle ⇧
路由如何在路由表中设置
title
- 搜索 google react router 6 set title
- How to change title of the page of React-Router v6+ in history menu
修改
@/pages/Home.tsx
|
|
路由组件中传参
@/route/routes.tsx
|
|
封装
@/hooks/useTitle.ts
|
|
修改
@/pages/Home.tsx
|
|
参考文章
- 初始代码:https://github.com/FrankFang/PntiAz
- 提交历史:https://github.com/FrankFang/TGZb6w/commits/master (新增5个提交)
- 最终代码:https://github.com/FrankFang/TGZb6w
相关文章
- 作者: Joel
- 文章链接:
- 版权声明
- 非自由转载-非商用-非衍生-保持署名