React中对数据的刷新

269 阅读1分钟

难点

如何在发送请求后实时更新数据

use-async.tsx

//? 处理 loading error

import { useState } from "react"


interface State<D> {
 data: D | null,
 error: Error | null,
 stat: "idle" | "loading" | "error" | "success"
}

const defaultInitralState: State<null> = {
 data: null,
 error: null,
 stat: 'idle'
}

// *配置参数 是否手动抛出错误
const defaultConfig = {
 throwError: false
}

export const useAsync = <D>(initialState?: State<D>, initialConfig?: typeof defaultConfig) => {
 const config = {
     ...defaultConfig,
     ...initialConfig
 }
 const [state, setState] = useState({
     ...defaultInitralState,
     ...initialState
 })

 const setDate = (data: D) => setState({
     data,
     error: null,
     stat: 'success'
 })

 const setError = (error: Error) => setState({
     data: null,
     error,
     stat: 'error'
 })

 // *发起异步请求
 const run = (promise: Promise<D>) => {
     if (!promise || !promise.then) {
         throw new Error('请传入 Promise 类型数据')
     }
     setState({ ...state, stat: "loading" })
     return promise.then(data => {
         setDate(data)
         return data
     }).catch(error => {

         setError(error)
         if (config.throwError)
             return Promise.reject(error)
         return error
     })
 }

 return {
     isLoading: state.stat === 'loading',
     isError: state.stat === 'error',
     run,
     ...state
 }
}

在发起请求后,我们如何实时的更新数据

方案一

我们可以重新请求 添加 retry 函数 ,即在run 后调用retry函数 重新请求数据。

但是我们该如何来写retry函数

如下所示:我们用useState来保存retry

    ...
    const [retey,setRetry] = useState(()=>{})

    // *发起异步请求
    const run = (promise: Promise<D>) => {
        if (!promise || !promise.then) {
            throw new Error('请传入 Promise 类型数据')
        }
        setRetry(()=>{ run(promise) })
        setState({ ...state, stat: "loading" })
        return promise.then(data => {
            setDate(data)
            return data
        }).catch(error => {

            setError(error)
            if (config.throwError)
                return Promise.reject(error)
            return error
        })
    }

    return {
        isLoading: state.stat === 'loading',
        isError: state.stat === 'error',
        run,
        retry,
        ...state
    }
}

如上,这样会有什么问题呢,根据useState的惰性初始化,initialState 参数只会在组件的初始渲染中起作用,后续渲染时会被忽略。如果初始 state 需要通过复杂计算获得,则可以传入一个函数,在函数中计算并返回初始的 state,此函数只在初始渲染时被调用。

所以我们要这么写

 ...
   const [retey,setRetry] = useState(()=>()=>{})

   // *发起异步请求
   const run = (promise: Promise<D>) => {
       if (!promise || !promise.then) {
           throw new Error('请传入 Promise 类型数据')
       }
       setRetry(()=>{()=>()=> run(promise) })
       setState({ ...state, stat: "loading" })
       return promise.then(data => {
           setDate(data)
           return data
       }).catch(error => {

           setError(error)
           if (config.throwError)
               return Promise.reject(error)
           return error
       })
   }

   ...