如何防止React中的`useEffect`函数由自定义钩子的函数引发的无限循环?

huangapple go评论67阅读模式
英文:

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 = () =&gt; {
  const func = () =&gt; {
      ...doSomething
    }

  return {
    func,
  };
};

export default useCustomHook;
const Component = () =&gt; {
  const router = useRouter();

  const customHook = useCustomHook();

  const { mutateAsync } = useMutation();

  const handleFunc = useCallback(async () =&gt; {
    if ( !router.isReady ) {
      return;
    }

    try {
      await mutateAsync();

      customHook.func();
    } catch (error) {
    }
  }, [
    mutateAsync,
    router.isReady,
    customHook,
  ]);

  useEffect(() =&gt; {
    handleFunc();
  }, [handleFunc]);

  return &lt;&gt;&lt;/&gt;;
};

export default Component;

答案1

得分: 2

useCustomHook 调用返回一个新对象,因此每次渲染都会更改它的引用。由于它也是 useCallback 函数 handleFunc 的依赖项,因此handleFunc 的引用也会在每次渲染时更改。因此,在 useEffect 中的依赖项仍然是它本身时,handleFunc 在每次渲染时都会被调用。

以下是避免无限循环的方法:

  1. useCustomHook 返回一个带有空数组依赖项的 useCallback 函数。
const useCustomHook = () => {
  const func = useCallback(() => {
      ...doSomething
  }, []);

  return {
    func,
  };
};

export default useCustomHook;
  1. 将回调函数 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:

  1. Make useCustomHook return a useCallback function with dependencies of an empty array.
const useCustomHook = () =&gt; {
  const func = useCallback(() =&gt; {
      ...doSomething
  }, []);

  return {
    func,
  };
};

export default useCustomHook;
  1. Use the callback function func as a dependency for handleFunc but not the hook object itself (or just omit it):
const Component = () =&gt; {
  const router = useRouter();

  const { func } = useCustomHook();

  const { mutateAsync } = useMutation();

  const handleFunc = useCallback(async () =&gt; {
    if (!router.isReady) {
      return;
    }

    try {
      await mutateAsync();
      func();
    } catch (error) {
    }
  }, [
    mutateAsync, 
    router.isReady, 
    func
  ]);

  useEffect(() =&gt; {
    handleFunc();
  }, [handleFunc]);

  return &lt;&gt;&lt;/&gt;;
};

export default Component;

huangapple
  • 本文由 发表于 2023年5月30日 09:45:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76361143.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定