0

I'm trying to arrange the data gotten from firebase but after I arrange it the app becomes slow and if I click on a button it gives an error saying "Excessive number of pending callbacks".

  useEffect(() => {
    if (chats.length && users.length) {
      const list = [];
      chats.forEach((chat) => {
        if (chat.members.includes(userId)) {
          chat.members.forEach((y) => {
            if (y !== userId) {
              console.log("receiver: " + y);
              users.forEach((z) => {
                if (z.id === y) {
                  console.log(z);
                  list.push({
                    chat: chat,
                    acc: z,
                    user: user
                  });
                }
              });
              console.log(list);
            }
          });
        }
      });

      setUserChats(list);
    }
  }, [chats, users]);

users and chats are both states that I got from firebase on snapshot also in useEffect

1 Answers1

1

One guess: Your dependencies don't work in the way you expect them to. chats and users aren't primitives, so depending on how they get created and passed, it's possible useEffect is run on every render, no matter whether chat and users have changed in structure or not. So this is what might happen:

  1. useEffect() will be called on every rerender due to your invalid dependencies.
  2. useEffect() calls setUserChats() on every turn. In theory, setUserChats() will check whether the new state actually differs, but in the same manner as useEffect it "fails" in the comparison and takes every list as a new state.
  3. setState() will trigger a new render. Rinse, repeat with 1)

What you need to understand it that useEffect checks whether dependencies have changed (and setUserChats() does so as well to decide whether new state actually differs from the old one). This check relies on the identity/equal reference, i.e. on oldValue === newValue. For non-primitive values that means: it doesn't matter if oldValue and newValue look alike or are perfect clones even - if they don't share the same address in the memory, they are taken as non-equal.

Check out this thread or this library for solutions. In your case, a simple (but not really nice) solution would be to change your dependencies to [JSON.stringify(chats), JSON.stringify(users)], but there are more elaborate, performant and reliable solutions out there.

(Additionally, you forget to add userId to the dependencies. So something like [userId, JSON.stringify(chats), JSON.stringify(users)] might be more appropriate.)

Another thought though: I don't see why all that logic requires to be put into a useEffect() anyway. Just calculate the list in the component itself and call setUserChats(list). Or does it take too long?

NotX
  • 1,516
  • 1
  • 14
  • 28