美文网首页
用自定义 hook 管理异步请求、状态

用自定义 hook 管理异步请求、状态

作者: 再见地平线_e930 | 来源:发表于2021-09-21 13:06 被阅读0次
    import { useState } from "react";
    
    interface State<D> {
      // 定义异步请求状态的接口
      data: D | null;
      error: Error | null;
      stat: "idle" | "loading" | "error" | "success"; // idle 表示未发生异步操作
    }
    
    const defaultInitialState: State<null> = {
      // 默认状态
      error: null,
      data: null,
      stat: "idle",
    };
    
    const defaultInitialConfig = {
      throwOnError: false, // 默认为不手动抛出异常,而是直接返回 error
    };
    
    /**
     * 管理异步状态的自定义 hook
     * @param 异步操作函数: Promise
     * @returns 异步获取的数据以及各种状态
     */
    export const useAsync = <D>(
      initialState?: State<D>,
      intialConfig?: typeof defaultInitialConfig
    ) => {
      const config = { ...defaultInitialConfig, ...intialConfig };
    
      const [state, setState] = useState<State<D>>({
        ...defaultInitialState,
        ...initialState,
      });
    
      const setData = (data: D) =>
        setState({
          // 异步请求成功的处理
          data,
          error: null,
          stat: "success",
        });
    
      const setError = (
        error: Error //这里的 error 只能在纯异步情况下使用,因为其本质是 useState,而 useState 是异步的
      ) =>
        setState({
          // 异步请求失败的处理
          data: null,
          stat: "error",
          error,
        });
    
      const run = (promise: Promise<D>) => {
        // run 用于触发异步请求,一般传入网络请求函数
        if (!promise || !promise.then) {
          // 如果没传入参数或传入的不是 Promise,报错
          throw new Error("请传入 Promise 类型数据"); // throw Error 会打断一切的进程,下面的代码也不会运行
        }
        setState({ ...state, stat: "loading" }); // 异步操作中,把状态设置为 loading
        return promise
          .then((data) => {
            setData(data);
            return data; // 这里可返回 data,也可不返回 data
          })
          .catch((error) => {
            setError(error);
            if (config.throwOnError) {
              return Promise.reject(error); // catch 会内部消化异常,外部不能通过 try catch 等方式捕获异常,因此这里要手动抛出异常
            }
            return error;
          });
      };
    
      return {
        isIdle: state.stat === "idle",
        isLoading: state.stat === "loading",
        isError: state.stat === "error",
        isSuccess: state.stat === "success",
        run,
        setData,
        setError,
        ...state,
      };
    };
    
    

    相关文章

      网友评论

          本文标题:用自定义 hook 管理异步请求、状态

          本文链接:https://www.haomeiwen.com/subject/efibgltx.html