英文:
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
useCustomHook
return auseCallback
function with dependencies of an empty array.
const useCustomHook = () => {
const func = useCallback(() => {
...doSomething
}, []);
return {
func,
};
};
export default useCustomHook;
- Use the callback function
func
as a dependency forhandleFunc
but 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;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论