简体   繁体   English

useEffect 依赖导致无限循环

[英]useEffect dependency causing an infinite loop

I am creating a simple agenda application that is hooked up to firebase as a backend.我正在创建一个简单的议程应用程序,它作为后端连接到 firebase。 I want to fetch the data on every write and I am trying to dodge an infinite loop.我想在每次写入时获取数据,并且试图避免无限循环。

useEffect(() => {
    const getTodos = () => {
      console.log("I will run");
      db.collection("Users")
        .doc(user.email)
        .collection("Todos")
        .get()
        .then((snapshot) => {
          const loadedTodos = snapshot.docs.map((docs) => {
            return {
              todo: docs.data().todo,
              isCompleted: docs.data().isCompleted,
              id: docs.id,
            };
          });
          setTodos(loadedTodos ?? []);
        });
    };
    getTodos();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [todos]);

The initial todos state is null.初始待办事项状态为空。 However, when I fetch the firebase data, it changes and then causes a rerender on the component itself which causes another fetch again causing an infinite loop.但是,当我获取 firebase 数据时,它会发生变化,然后导致组件本身重新渲染,从而导致再次获取导致无限循环。 I have broke the limit of the spark plan in firebase because of this and wasted days of work because of temporary blocks.由于这个原因,我打破了 firebase 中 spark 计划的限制,并因临时阻塞而浪费了几天的工作。 I think this can be fixed with the useCallback hook, but I do not know how.我认为这可以通过 useCallback 钩子解决,但我不知道如何解决。 Also, I want to add the same functionality with a chat application (where data will be written from two sides).此外,我想为聊天应用程序添加相同的功能(数据将从两侧写入)。 Is it possible to rerender only when one of the two sides has written or does it have to be an infinite loop in such a case?是否可以仅在两侧之一已写入时重新渲染,或者在这种情况下必须是无限循环?

The dependency you want in your effect is user.email你想要的效果依赖是user.email

useEffect(() => {
   const getTodos = () => {
     console.log("I will run");
     db.collection("Users")
       .doc(user.email)
       .collection("Todos")
       .get()
       .then((snapshot) => {
         const loadedTodos = snapshot.docs.map((docs) => {
           return {
             todo: docs.data().todo,
             isCompleted: docs.data().isCompleted,
             id: docs.id,
           };
         });
         setTodos(loadedTodos ?? []);
       });
   };
   getTodos();
 }, [user.email]);

You can read this as: every time user.email changes, I will want to refetch the to-do list.您可以将其理解为:每次user.email更改时,我都想重新获取待办事项列表。

EDIT: The reason you are observing an infinite loop, as others have said, is because your effect's dependency gets changed by the effect itself, which causes the effect to run again.编辑:正如其他人所说,您观察到无限循环的原因是因为效果本身改变了效果的依赖关系,这会导致效果再次运行。 This can often be fixed by "lifting state up" - but in this case, it's because you're using the wrong dependency.这通常可以通过“提升状态”来解决 - 但在这种情况下,这是因为您使用了错误的依赖项。

I just added a new useState hook, shouldComponentRerender, that changes whenever a function of (addTodos, deleteTodo, setCompletionState) is called, and then the shouldComponentRerender state was added as a dependency for the useEffect hook.我刚刚添加了一个新的 useState 挂钩,shouldComponentRerender,它会在调用 (addTodos, deleteTodo, setCompletionState) 的函数时发生变化,然后将 shouldComponentRerender 状态添加为 useEffect 挂钩的依赖项。 Gave me the result I wanted.给了我想要的结果。 Thanks!谢谢!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM