最近在学习React,遇到一个异步请求的场景,尝试着写了一个hook处理异步操作——useAsync
异步状态类型限制
interface StateProps<D> {
error: Error | null
data: D | null
status: 'idle' | 'loading' | 'error' | 'success'
}
此处泛型D是该异步操作中的数据类型,error记录出现的错误和异常,status便是异步状态
默认初始化异步状态
const defaultInitialState: StateProps<null> = {
data: null,
status: 'idle',
error: null
}
useAsync
export const useAsync = <D>(initialState?: StateProps<D>) => {
const [state, setState] = useState<StateProps<D>>({
...defaultInitialState,
...initialState })
const setData = (data: D) => setState({
data,
status: 'success',
error: null })
const setError = (error: Error) => setState({
error,
data: null,
status: 'error' })
const run = (promise: Promise<D>) => {
if (!promise || !promise.then) {
throw new Error('Please provide a parameter of type Promise!')
}
setState({
...state,
status: 'loading'
})
return promise.then(data => {
setData(data)
return data
}).catch(err => {
setError(err)
return err
}) }
return {
isIdle: state.status === 'idle',
isLoading: state.status === 'loading',
isSuccess: state.status === 'success',
isError: state.status === 'error',
run,
setData,
setError,
...state }
}
定义setData和setError用于在异步完成返回数据和遇到错误是更新状态,run用于暴露给外界执行他们传入的异步操作,在上述几个函数中都需要根据情况更改状态status,最后将相关操作的函数和数据暴露出去供外部使用。
实践
假设我有一个获取后台数据的方法,如下
const fetchData = (param: ParamProps) => {
return new Promise<DataProps[]>((resolve, reject) => {
fetch(`${BASE_URL}/xxxx?${Utils.qsStringify(param)}`).then(
async res => {
if (res.ok) {
resolve(await res.json())
} else {
reject(new Error('请求失败!请检查网络或后台设置'))
} }).catch(() => {
reject(new Error('请求失败!请检查网络或后台设置')) }) })}
该方法便是一个异步操作,我可以将其放到上面自定义的useAsync使用
const { run, isLoading, data, error } = useAsync<DataProps[]>()
// 依赖参数param触发调用
useEffect(() => { run(fetchProjects(param)) }, [param])
此时自定义hook——useAsync暴露给我的数据便可以使用
{error ? (
<MyErrorTips type={'danger'}>{error.message}</MyErrorTips>
) : null} <MyDataTable loading={isLoading} dataSource={data || []} />
使用useAsync获取的error判断请求是否出现异常错误,获取的data依赖于param,无论何时param参数变化你都会获取得到想要的data,然后渲染数据即可。使用hook抽象后页面代码更简洁精练,并且任何时候任何组件中需要都可以使用,大大提高了开发写代码的效率和可读性。