Reactjs 防止“useEffect”循环

Reactjs 防止“useEffect”循环,reactjs,firebase-authentication,react-hooks,use-effect,Reactjs,Firebase Authentication,React Hooks,Use Effect,我有一个简单的Useffect,我不知道如何停止无休止的调用。它不断地发射第一个信号,如果有条件的话。我已经读了很多关于钩子的书,我可能错误地认为组件的每个呈现都会导致对我的useAuth和useUser钩子的新调用。因为它们在内存中有新的引用,它触发了useEffect的deps,因为从技术上讲,它是一个新函数,存在于这个新组件render的范围内 至少这是我的想法,如果真的是那样的话,我不知道如何解决这个问题 const RootPage = ({ Component, pageProps

我有一个简单的Useffect,我不知道如何停止无休止的调用。它不断地发射第一个信号,如果有条件的话。我已经读了很多关于钩子的书,我可能错误地认为组件的每个呈现都会导致对我的useAuth和useUser钩子的新调用。因为它们在内存中有新的引用,它触发了useEffect的deps,因为从技术上讲,它是一个新函数,存在于这个新组件render的范围内

至少这是我的想法,如果真的是那样的话,我不知道如何解决这个问题

const RootPage = ({ Component, pageProps }): JSX.Element => {
  const { logoutUser } = useAuth();  // imported
  const { fetchUser } = useUser();   // imported
  const router = useRouter();

  useEffect(() => {
    // authStatus();
    const unsubscribe = firebaseAuth.onAuthStateChanged((user) => {
      if (user) {
        console.log(1);
        return fetchUser(user.uid); // async function that fetches from db and updates redux
      }
      console.log(2);
      return logoutUser(); // clears userData in redux
    });
    return () => unsubscribe();
  }, [fetchUser, logoutUser]);

  ...
}
获取用户

注销用户

当我使用此useEffect刷新页面时,会将其输出到控制台:


使用useCallback将fetchUser和resetUser保持不变&&wrapping,此解决方案似乎工作正常。我现在还不完全清楚为什么。

在自定义挂钩中,需要在useCallback中包装logoutUser和fetchUser函数。请查看useCallback文档以获取解释。如果该效果持续触发,可能是因为其依赖项正在更改,也可能是因为您正在安装新组件。。。很难说没有看到更多的代码。实际上,我想可能是我用UseCallback包装了一个错误的函数,whoopsUsecallback阻止函数被重新定义,除非依赖项数组中的一个依赖项发生变化。因此,不会在每次渲染时重新定义包装函数,从而防止在每次渲染时触发useEffect。你基本上是在记忆函数。这是有道理的,我认为useCallback必须在组件主体内调用,但显然它也可以在自定义钩子内调用。没错,虽然从技术上讲它只能在组件主体内调用,因为钩子只在组件主体内调用。是一样的。
  const fetchUser = async (uid) => {
    try {
      // find user doc with matching id
      const response = await firebaseFirestore
        .collection('users')
        .doc(uid)
        .get();
      const user = response.data();
      // update redux with user
      if (response) {
        return dispatch({
          type: FETCH_USER,
          payload: user,
        });
      }
      console.log('no user found');
    } catch (error) {
      console.error(error);
    }
  };
  const logoutUser = async () => {
    try {
      // logout from firebase
      await firebaseAuth.signOut();
      // reset user state in redux
      resetUser();
      return;
    } catch (error) {
      console.error(error);
    }
  };
  useEffect(() => {
    function onAuthStateChange() {
      return firebaseAuth.onAuthStateChanged((user) => {
        if (user) {
          fetchUser(user.uid);
        } else {
          resetUser();
        }
      });
    }
    const unsubscribe = onAuthStateChange();
    return () => {
      unsubscribe();
    };
  }, [fetchUser, resetUser]);