【问题标题】:Infinite loop in a custom useFetch hook自定义 useFetch 挂钩中的无限循环
【发布时间】:2020-09-09 17:08:46
【问题描述】:

所以我不确定,究竟是什么原因导致此问题或如何正确解决此问题。

我有一个自定义的 useFetch 挂钩来获取数据。唯一的特别之处是您可以提供一个函数来修改 fetch 的结果。 useFetch 钩子是由我无法再联系的某个人编写的。

这里有一个完整的、独立的代码框示例来重现这个:

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

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

在组件内部的 init-object 中进行注释时,useFetch 挂钩开始无限获取 url。

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

【问题讨论】:

  • 问题是,为什么要在App功能里面设置init呢?在外面进行操作按预期工作。
  • 因为在实际应用程序中,它没有在某处定义为 const,而是由具有来自组件状态的一些参数的函数调用。

标签: javascript reactjs react-hooks render


【解决方案1】:

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

 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;
}

【讨论】:

  • 谢谢。所以不管你提到的 effekt-hook 发生了什么,只要在组件中定义了对象,它就会无限循环,对吧?
  • 适合您的情况。因此,如果不可能,您应该在组件外部创建对象或添加useMemo。 PS:从技术上讲,如果效果不触发重新渲染(即它只是console.log),它不会创建无限循环。
猜你喜欢
  • 1970-01-01
  • 2021-12-16
  • 2023-02-06
  • 2022-09-27
  • 1970-01-01
  • 1970-01-01
  • 2023-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多