Reputation: 85
I am experiencing a strange problem with firebase Realtime DB.problem is with a chat component.
componentDidMount(){
this.renderMessages();
}
renderMessages(){
rdb.ref("chats/"+this.props.id).orderByChild("time").on('child_added', (snapshot)=>{
if(snapshot.exists)
{
this.setState({messages [...this.state.messages,snapshot.val()]})
}
})
}
then map through this state and pass data to other components and everything works fine on the first run.
consoled Object On the first run [ it is an array of objects ]
0: Object { message: "hello", read: false, sender: "Shan", …
1: Object { message: "Hai Shan", read: false, sender: "AashiqOtp", … }
2: Object { message: "hi", read: false, sender: "AashiqOtp", … }
when I go back and re-entered into the component it then it only shows the last object of the array ie
0: Object { message: "hi", read: false, sender: "AashiqOtp", … }
what's the issue? can someone help me out? Thanks in advance.
UPDATED
I am using " .once " event listener there are no problems, but as it is a chat component I need to always listen to the event.
Upvotes: 0
Views: 131
Reputation: 1788
This is issue related to state not updating fast enough. You should use an updater function, if your new state is based on the old one.
Also, you shouldn't call this.setState
multiple times in the forEach
and instead add the whole array at once, to avoid many unnecessary rerenders and issues like this one
renderMessages(){
rdb.ref("chats/"+this.props.id).on('value', (snapshot) => {
this.setState(prevState => ({
messages: [
...prevState.messages,
...snapshot
.filter((childsnap) => childsnap.exists)
.map((childsnap) => childsnap.val())
]
}))
})
}
Since you changed the event in the question, there is no way to add the whole array at once and you have to use the less efficient method:
renderMessages(){
rdb.ref("chats/"+this.props.id).orderByChild("time").on('child_added', (snapshot) => {
if (snapshot.exists) {
this.setState(prevState => ({
messages: [
...prevState.messages,
snapshot.val()
]
}))
}
})
}
Upvotes: 1