2

I am getting the error below. I assume this is because I'm still subscribed to the Firebase database even when my component unmounts. I am trying to take advantage of the real-time features so that whenever an item is deleted from the list it will reflect on the UI.

enter image description here

I have created multiple functions with a single purpose to fetch different documents. Below is one example.

export const getAllTask = (userId) => {
  return new Promise((resolve, reject) => {
    const db = database.ref('tasks');

    db.child(`${userId}/taskItems`).on('value', (snapshot) => {
      const user = snapshot.val();
      if (user) {
        resolve(user);
      } else {
        reject(user);
      }
    });
  });
};

Then whenever any of my components, it runs my useEffect to fetch data however when it unmounts how can I correctly use off() or clean up correctly? Is there a better approach to do this?

useEffect(() => {
  const test = async (userId) => {
    await getAllTask(userId).then((result) => {
      setItems(result);
    });
  };
  test(userId);
}, [userId]);
Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62
Freddy.
  • 1,593
  • 2
  • 20
  • 32

2 Answers2

0

try this ,useEffect returns a function that is called when component unmounts

useEffect(() => {
     let mounted=true;
    const test = async (userId) => {
       await getAllTask(userId).then((result) => {
         if(mounted) setItems(result)
      });
    };
   test(userId);
   return ()=>{mounted=false}
  }, [userId]);
سعيد
  • 1,547
  • 1
  • 14
  • 32
0

In this case, you shouldn't use on() at all. Use once() for reading data a single time. It returns a promise that's easy to work with. on() is for persistent listeners that deliver updates over time every time something changes with the results of the query.

Since promises can only resolve a single time, it doesn't make sense to wrap a persistent listener in a promise.

If you do actually want listener updates over time, for as long as the component is mounted, don't wrap it in a promise. instead, you should instruct your useEffect to unsubscribe the listener by returning a function that it can invoke to shut things down.

See also: How to properly update state with Firebase and useEffect()? In the answer there, see how the useEffect hook returns a function that calls off().

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • On component mount, I get all user tasks, and within that component, there is an input field where I can add to this list and it will appear on the component, it is better off to implement from the example you provided? – Freddy. Nov 03 '20 at 15:56
  • I was hoping to create a singular function in which I only pass the path and userId to fetch data. This is why I tried to implement it this way so its reusable – Freddy. Nov 03 '20 at 16:05
  • As I said, it will be easier for you to use once() instead of on() since it returns a promise. – Doug Stevenson Nov 03 '20 at 16:52