Reputation: 10055
I never find a solution for my useEffect probleme :
I'm useing firebase and create a listener (onSnapshot) on my database to get the last state of my object "Player" I can get when the states currentGroup
and currentUser
are available
const [currentGroup, setCurrentGroup] = useState(null)
const [currentUser, setCurrentUser] = useState(null)
const [currentPlayer, setCurrentPlayer] = useState(null)
const IDefineMyListener = () =>{
return firebase.doc(`group/${currentGroup.id}${users/${currentUser.id}/`)
.onSnpashot(snap =>{
//I get my snap because it changed
setCurrentPlayer(snap.data())
})
}
Juste above, i call a useEffect when the currentGroup
and currentUser
are available and (IMPORTANT) if I didn't already set the currentPlayer
useEffect(() => {
if (!currentGroup || !currentUser) return
if (!currentPlayer) {
let unsubscribe = IDefineMyListener()
return (() => {
unsubscribe()
})
}
},[currentGroup,currentUser])
As you can think, unsubscribe()
is called even if the IDefineMyListener()
is not redefined. In other words, when currentGroup
or currentUser
changes, this useEffect
deleted my listener whereas I NEED IT.
How can i figure out ?!
PS :if I remove if (!currentPlayer)
, of course it works but will unlessly get my data
PS2 : If I remove the unsubscribe, my listener is called twice each time.
Upvotes: 0
Views: 2525
Reputation: 10055
The problem was about my bad understanding of the unsubscribe() . I didn't return anything in my useEffect, but save my unsusbcribe function to call it when i need.
let unsubscribe = null //I will save the unsubscription listener inside it
const myComponent = () => {
const [currentGroup, setCurrentGroup] = useState(null)
const [currentUser, setCurrentUser] = useState(null)
const [currentPlayer, setCurrentPlayer] = useState(null)
useEffect(() => {
if (!currentGroup || !currentUser) {
if(unsubscribe){
unsubscribe() // 2 - when I dont need of my listener, I call the unsubscription function
}
return
}
if (!currentPlayer && !unsubscribe) {
unsubscribe = IDefineMyListener() // 1 - I create my listener and save the unsubscription in a persistant variable
}
},[currentGroup,currentUser])
const IDefineMyListener = () =>{
return firebase.doc(`group/${currentGroup.id}${users/${currentUser.id}/`)
.onSnpashot(snap =>{
//I get my snap because it changed
setCurrentPlayer(snap.data())
})
}
...
Upvotes: 1
Reputation: 2889
You can use useCallback
hook to work around this.
First we'll define your listener using useCallback
and give the dependency array the arguments as currentGroup
and currentUser
.
const IDefineMyListener = useCallback(event => {
return firebase.doc(`group/${currentGroup.id}${users/${currentUser.id}/`)
.onSnpashot(snap =>{
//I get my snap because it changed
setCurrentPlayer(snap.data())
})
}, [currentGroup, currentUser]);
And we will only use useEffect
to register and deregister your listener.
useEffect(() => {
//subscribe the listener
IDefineMyListener()
return (() => {
//unsubscribe the listener here
unsubscribe()
})
}
},[])
Since we passed an []
to useEffect, it will only run once when the component is mounted. But we have already registered the callback. So your callback will run everytime the currentGroup
or currentUser
changes without deregistering your listener.
Upvotes: 5