自定义 useFetch 挂钩中的无限循环

Infinite loop in a custom useFetch hook

所以我不确定,到底是什么原因造成的,或者如何正确解决这个问题。

我有一个自定义的 useFetch 挂钩来获取数据。它唯一特别的地方是你可以提供一个函数来修改获取的结果。 useFetch 挂钩是由我无法联系到的某个人编写的。

这是一个完整的、独立的 codesandbox 示例来重现此内容:

https://codesandbox.io/s/optimistic-lalande-glhg3?file=/src/App.js:192-326

您可以看到所选行 (192-326) 已被注释掉。它是组件上方对象的副本。

在组件内部的初始化对象中注释时,useFetch 挂钩开始无限获取 url。

这可能与变量或值的更改/重新渲染有关,但我不明白。

每次渲染都会使用新引用创建新对象 init,但内容相同。然后这个效果跟踪这个 ref 并执行状态更新。因此状态更新导致 re-render,这导致触发效果的新初始化对象 ...

 useEffect(() => {
    setLoading();
    [...successModifiers, (result) => setResource(result)].reduce(
      (previous, current) => previous.then(current).catch(setError),
      fetch(url, init).catch((error) => setError(error))
    );
  }, [url, init, successModifiers]);
//         ^^^^^

要解决它,您可以使用 useMemo:

持久化对象引用

const init = useMemo(() => ({ /*...*/ }));

但这会使 useFetch 的用法有点笨拙,因此替代方法是根据深度比较将对象持久化到 useFetch 中。像这样:


function useDeepMemo(object) {
  const ref = useRef(object);

  if (!deepEquals(object, ref.current)) {
    ref.current = object;
  }

  return ref.current;
}