备战面试!在TypeScript中封装获取redux里数据的Hooks

336 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

我们经常会遇到一进入页面就要发请求获取数据的情况,而且一个项目往往不止一个,所以要封装一个Hooks,简化这些代码,完成程序员的使命:消除重复代码

先看看没封装前的代码,我们需要写这么多行来完成发请求获取数据的动作

import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { getUserProfile } from '@/store/actions'
import type { RootState } from '@/types/store'
const dispatch = useDispatch()
const { userProfile } = useSelector((state: RootState) => state.profile)
useEffect(() => {
dispatch(getUserProfile())
}, [dispatch])

发现只要需求是一进页面发送请求获取数据,就是这几步,所以我们需要封装一个Hooks 1、分析要封装的代码逻辑,找出要封装的代码的相同点和不同点。函数封装的基本思想:将相同的逻辑直接拷贝到函数中,不同的逻辑通过函数参数传入。需要返回数据,就通过函数返回值返回

image.png

分发的 action 函数不同、获取的状态不同,所以这两个要作为参数调用时传入,其他的代码逻辑封装进函数

在hooks/useInitState.ts 中封装hooks:

import { RootState } from '@/types/store'
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
// T extends keyof RootState继承RootState的键名,stateName:T约定传过来的参数也只能是RootState的键名
export default function useInitState<T extends keyof RootState> (action:()=>void, stateName:T) {stateName//是state里的状态值,也叫模块名,因为多个模块,state里有多个状态
const dispatch = useDispatch()
useEffect(() => {
dispatch(action())//action传入分发的action函数
}, [])
// state[stateName]====state里放的是个变量,直接写.等于是字符串
return useSelector((state:RootState) => state[stateName])// 这里return的是state.profile这个对象
}

封装完成调用就很方便!

import useInitState from '@/hooks/useInitState' //导入hooks
import { getUserProfile } from '@/store/actions/profile' //导入action对应分发的函数
 直接传入分发函数和我们需要获取的状态即可
 const { userProfile: user } = useInitState(getUserProfile, 'profile') // 得到的是profile这个对象,对象里面有user和userProfile两个对象

注意点添加类型约束 因为是在ts里面写,需要我们添加类型约束

对于useInitState这个自定义 hook 来说,只需要为参数指定类型即可。

1、参数 action:就是一个函数,所以,直接指定为最简单的函数类型即可

2、 参数 stateName:

  • stateName 表示从 Redux 状态中取出的状态名称,比如,'profile'
  • 所以,stateName 应该是 RootState 中的所有状态名称中的任意一个
  • 但是,具体是哪一个不确定,只有在使用该函数时才能确定下来。 建议一开始不确定类型的时候,可以统一any大法,保证代码逻辑没问题,再来确定类型