【问题标题】:Let State update before running async function在运行异步函数之前让状态更新
【发布时间】:2023-03-31 10:40:01
【问题描述】:

我有一个 useFetch 钩子。如果在数据未决时再次调用 fetchData 函数,则调用 controller.abort() 并重新运行该函数。唯一的问题是 React 更新调度函数的速度不够快。我怎样才能做到这一点,以便在调用 controller.abort() 函数时,它会等到所有状态更改完成后再重新运行 fetchData 函数。我使用 useEffect 对其进行了拍摄,但无法使其正常工作。谢谢!

 export const useFetchStats = (callNumber: number, params?: any) => {
  const { statsDispatch } = useAppState();
  const [error, setError] = useState(null);
  const [status, setStatus] = useState<any>(null);
  const [isLoading] = useState(false);

  const newUrl = new URL(`${process.env.REACT_APP_STATS_ENDPOINT}${statsCalls[callNumber].url}`
  );


  const dispatch: any = statsCalls[callNumber].type;
  let controller: any = null;

  const fetchData = async () => {
    controller = new AbortController();
    const requestOptions: RequestInit = {
      method: "GET",
      headers: myHeaders,
      redirect: "follow",
      signal: controller.signal,
    };

    statsDispatch({ type: dispatch, isLoading: true });
    try {
      const res = await fetch(newUrl.href, requestOptions);
      setStatus(res);
      const json = await res.json();
      statsDispatch({ type: dispatch, data: json });
    } catch (error) {
      setError(error);
    } finally {
      statsDispatch({ type: dispatch, isLoading: false });
    }
  };

  const abortFetch = () => {
    controller && controller.abort();
  };

  useEffect(() => {
    fetchData();
  }, [abortFetch]);

  return [fetchData, isLoading, abortFetch, error, status];
};

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    您定义controller 的方式可能会过时,因为每次更新都会重新分配它,因此请改用useRef,以便它在更新中保持并保持对原始值的引用。此外,useEffect 缺少 fetchData 依赖项,我看不到在哪里或是否曾经调用过 abortFetch。这些是它不起作用的一些原因。以下是我的建议:

    控制器的useRef:

      const controllerRef = useRef();
      const fetchData = async () => {
        controllerRef.current = new AbortController();
        const controller = controllerRef.current;
        const requestOptions: RequestInit = {
          method: "GET",
          headers: myHeaders,
          redirect: "follow",
          signal: controller.signal
        };
       // function body
      };
    
      const abortFetch = () => {
        controllerRef.current && controllerRef.current.abort();
      };
    

    将取消移动到 fetchData:

    如果您想确保调用fetchData 取消之前的fetchData,请考虑将abortFetch 添加到fetchData 的第一行,以便在它尝试获取任何内容之前,取消当前正在进行的任何内容。

     const fetchData = async () => {
        // cancel anything if it exists
        controllerRef.current && controllerRef.current.abort();
        controllerRef.current = new AbortController();
         // function body 
     }
    

    fetchData 应如下所示:

      const controllerRef = useRef();
      const fetchData = async () => {
        controllerRef.current && controllerRef.current.abort();
        controllerRef.current = new AbortController();
        const controller = controllerRef.current;
        const requestOptions: RequestInit = {
          method: "GET",
          headers: myHeaders,
          redirect: "follow",
          signal: controller.signal
        };
    
        statsDispatch({ type: dispatch, isLoading: true });
        try {
          const res = await fetch(newUrl.href, requestOptions);
          setStatus(res);
          const json = await res.json();
          statsDispatch({ type: dispatch, data: json });
        } catch (error) {
          setError(error);
        } finally {
          statsDispatch({ type: dispatch, isLoading: false });
        }
      };
    

    将从useFetchStatsfetchDataabortFetch)返回的函数包装在useCallbacks 中,以便它们始终是最新的:

      const fetchData = useCallback(async () => {
        // function body
      }, [newUrl.href, statsDispatch]);
    
      const abortFetch = useCallback(() => {
        controllerRef.current && controllerRef.current.abort();
      }, []);
    

    【讨论】:

    • 感谢您的详细解答。我可以看到这是取消请求的更安全的方法。我唯一的问题是,当函数取消请求时,加载状态设置为 false,并且在函数再次启动时不会设置回 true。有没有办法可以保证它被设置为 true?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-08
    • 2017-04-20
    • 2017-05-12
    • 2022-01-23
    • 1970-01-01
    • 2023-01-28
    相关资源
    最近更新 更多