Reputation: 147
Background: This is a practice todo list app where I'm using onValue to listen to changes to the list of todos in realtime database, and then mapping that onto a tasks array in the front end.
I previously had a memory leak error appear when using onValue in the following manner - when I didn't unsubscribe from my onValue listener:
useEffect(
() => {
if (user) {
onValue(ref(database, `users/${user}/tasks`), (snapshot) => {
const todos = snapshot.val();
const tasks = [];
for (let id in todos) {
tasks.push({ ...todos[id], id: id })
}
setTasks(tasks)
})
} else {
setTasks([])
}
}, [user])
I saw from some other questions here that onValue returns an unsubscribe function, and I also saw an answer that by adding return to the onValue line, I could unsubscribe from it - I've tried to do this below:
useEffect(
() => {
if (user) {
return onValue(ref(database, `users/${user}/tasks`), (snapshot) => {
const todos = snapshot.val();
const tasks = [];
for (let id in todos) {
tasks.push({ ...todos[id], id: id })
}
setTasks(tasks)
})
} else {
setTasks([])
}
}, [user])
It seems to work for me, but could I get some help to confirm that this is the proper way to unsubscribe from this onValue listener?
Upvotes: 1
Views: 2688
Reputation: 65
With Web v9, the result of an onValue()
call is the 'unsubscriber'.
const unsubscribe = onValue(ref(database, `sessions/${session}`), (snapshot) => {
const sessionData= snapshot.val();
if( sessionData.status === 'over' )
{
// remove the listener
unsubscribe();
}else{
// Do something with the snapshot data
}
})
Edit : While this information is unfortunately omitted from firebase documentation, the firebase api reference of onValue clearly shows that it returns Unsubscriber https://firebase.google.com/docs/reference/js/database.md#onvalue
onValue()
Returns:
Unsubscribe
A function that can be invoked to remove the listener.
Upvotes: 1
Reputation: 598728
Your useEffect
callback needs to return an unsubscribe function, so that React can call that when the component/hook is no longer needed. By returning the return value from onValue
, you ensure that the onValue
gets unsubscribed when the component/hook is no longer needed. If that is what you want to accomplish (which seems the case), then this indeed looks correct.
Upvotes: 3