自定义 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;
}
所以我不确定,到底是什么原因造成的,或者如何正确解决这个问题。
我有一个自定义的 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;
}