英文:
How do I prevent an infinite loop in the useEffect function in React caused by a custom hook's function?
问题
在以下代码中,useEffect 中的 mutateAsync 由于自定义钩子中的函数而无限调用。你能告诉我为什么吗?
const useCustomHook = () => {
const func = () => {
...做一些操作
}
return {
func,
};
};
export default useCustomHook;
const Component = () => {
const router = useRouter();
const customHook = useCustomHook();
const { mutateAsync } = useMutation();
const handleFunc = useCallback(async () => {
if (!router.isReady) {
return;
}
try {
await mutateAsync();
customHook.func();
} catch (error) {
}
}, [
mutateAsync,
router.isReady,
customHook,
]);
useEffect(() => {
handleFunc();
}, [handleFunc]);
return <></>;
};
export default Component;
英文:
I have a question about React.
In the following code, mutateAsync in useEffect is called infinitely due to the function in the custom hook. Can you tell me why?
const useCustomHook = () => {
const func = () => {
...doSomething
}
return {
func,
};
};
export default useCustomHook;
const Component = () => {
const router = useRouter();
const customHook = useCustomHook();
const { mutateAsync } = useMutation();
const handleFunc = useCallback(async () => {
if ( !router.isReady ) {
return;
}
try {
await mutateAsync();
customHook.func();
} catch (error) {
}
}, [
mutateAsync,
router.isReady,
customHook,
]);
useEffect(() => {
handleFunc();
}, [handleFunc]);
return <></>;
};
export default Component;
答案1
得分: 2
useCustomHook 调用返回一个新对象,因此每次渲染都会更改它的引用。由于它也是 useCallback 函数 handleFunc 的依赖项,因此handleFunc 的引用也会在每次渲染时更改。因此,在 useEffect 中的依赖项仍然是它本身时,handleFunc 在每次渲染时都会被调用。
以下是避免无限循环的方法:
- 让
useCustomHook返回一个带有空数组依赖项的useCallback函数。
const useCustomHook = () => {
const func = useCallback(() => {
...doSomething
}, []);
return {
func,
};
};
export default useCustomHook;
- 将回调函数
func用作handleFunc的依赖项,但不是钩子对象本身(或者只是省略它):
const Component = () => {
const router = useRouter();
const { func } = useCustomHook();
const { mutateAsync } = useMutation();
const handleFunc = useCallback(async () => {
if (!router.isReady) {
return;
}
try {
await mutateAsync();
func();
} catch (error) {
}
}, [
mutateAsync,
router.isReady,
func
]);
useEffect(() => {
handleFunc();
}, [handleFunc]);
return <></>;
};
export default Component;
英文:
customHook from useCustomHook() call returns a new object, so its reference changes every render. Since its also a dependency of useCallback function handleFunc, so the reference of handleFunc also changes every render. Thus handleFunc gets called every render in the useEffect while the dependency is itself.
Here's what you could do to avoid the infinite loop:
- Make
useCustomHookreturn auseCallbackfunction with dependencies of an empty array.
const useCustomHook = () => {
const func = useCallback(() => {
...doSomething
}, []);
return {
func,
};
};
export default useCustomHook;
- Use the callback function
funcas a dependency forhandleFuncbut not the hook object itself (or just omit it):
const Component = () => {
const router = useRouter();
const { func } = useCustomHook();
const { mutateAsync } = useMutation();
const handleFunc = useCallback(async () => {
if (!router.isReady) {
return;
}
try {
await mutateAsync();
func();
} catch (error) {
}
}, [
mutateAsync,
router.isReady,
func
]);
useEffect(() => {
handleFunc();
}, [handleFunc]);
return <></>;
};
export default Component;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论