How to correctly clean up function when fetching Firebase database() on()?

Viewed 286

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]);
2 Answers

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]);

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().

Related