在写React 项目业务过程中,经常写一些 相似的代码逻辑。
比如我需要在进入页面请求接口数据
传统上我们请求接口获取数据,大概类似这样:
/** 数据 */
const [detail, setDetail] = useState(defaultData)
/** 请求数据 */
const mutate = async () => {
try {
const { data } = await config.getData({ ...params })
setDetail(data)
} catch (error) {}
}
useEffect(() => {
mutate()
}, [])
对于这类相关的业务逻辑,我写了一个自定义hooks
/** hooks - 对于简单的获取数据方法的一个封装 */
import { useState, useRef, useEffect, useMemo } from 'react'
interface IMutateOption<T> {
/** 默认数据 */
defaultData?: T
/** 额外传递参数 */
params?: Record<string, any>
/** 初始是否发出请求 */
initRequest?: boolean
/** 获取数据 */
getData: (data: Record<string, any>) => Promise<{ data?: T }>
/** 数据格式化 */
dataFormat?(data?: T): any
/** 请求成功后的回调 */
successCallback?(data?: T): void
}
export function useMutate<T>(config: IMutateOption<T>) {
const { defaultData, params, initRequest = true } = config
/** 数据 */
const [detail, setDetail] = useState(defaultData)
/** 是否初始化 */
const isInit = useRef(initRequest)
let loading = false
/** 请求数据 */
const mutate = async () => {
try {
loading = true
const { data } = await config.getData({ ...params })
const newData = config.dataFormat ? config.dataFormat(data) : data
setDetail(newData)
config?.successCallback?.(newData)
return newData
} catch (error) {
setDetail({})
} finally {
loading = false
}
}
/** 初始请求 */
useEffect(() => {
if (!isInit.current) {
isInit.current = true
} else {
mutate()
}
}, [])
/** 暂无数据 */
const noData = useMemo(() => {
if (detail !== undefined) {
if (detail instanceof Array) {
return detail.length === 0
} else if (detail instanceof Object) {
return Object.keys(detail).length === 0
}
}
return false
}, [detail])
return { mutate, detail, setDetail, noData, loading }
}
获取数据类似逻辑简单封装
