by using useEffect, my array state variable did not append the previous value, but componentDidMount did
I console.log out the message when using the useEffect, and all the message were correctedly printed out, but the state wasn't stored, if I set the messages state variable as the dependency of the useEffect, it goes into an infinite loop
// with useEffect hook
function App() {
const [messages, setMessages] = useState([]);
useEffect(() => {
const chatManager = new ChatManager({
instanceLocator: instanceLocator,
userId: 'Henry',
tokenProvider: new TokenProvider({
url: tokenUrl
})
});
chatManager.connect()
.then(currentUser => {
currentUser.subscribeToRoomMultipart({
roomId: '7b7a1d23-e869-4c19-8eab-e88d5144dd72',
hooks: {
onMessage: message => {
console.log([...messages]);
setMessages([...messages, message]);
}
}
})
}).catch(err => {
console.log('Error on connection', err)
})
}, [])
return (
<div className="app">
<RoomList />
<MessageList messages={messages}/>
<SendMessageForm />
<NewRoomForm />
</div>
);
}
export default App;
// with componentDidMount
class App extends React.Component {
constructor() {
super()
this.state = {
messages: []
}
}
componentDidMount() {
const chatManager = new ChatManager({
instanceLocator,
userId: 'Henry',
tokenProvider: new TokenProvider({
url: tokenUrl
})
})
chatManager.connect()
.then(currentUser => {
currentUser.subscribeToRoomMultipart({
roomId: '7b7a1d23-e869-4c19-8eab-e88d5144dd72',
hooks: {
onMessage: message => {
this.setState({
messages: [...this.state.messages, message]
})
}
}
})
})
}
render() {
return (
<div className="app">
<RoomList />
<MessageList messages={this.state.messages} />
<SendMessageForm />
<NewRoomForm />
</div>
);
}
}
export default App
I expect the result of using useEffect the same as componentDidMount which hash all the message inside the messages state array variable, yet by using useEffect, I can console out all the message, but the messages state array variable is empty so the final result is only the latest message.
Since your state depends on the current state value, you need to use the functional form of setMessages
. This means you don't need to include messages
as a dependency (because it actually won't be a dependency):
useEffect(() => {
...
chatManager.connect()
.then(currentUser => {
currentUser.subscribeToRoomMultipart({
roomId: '7b7a1d23-e869-4c19-8eab-e88d5144dd72',
hooks: {
onMessage: message => {
setMessages(prevMessages => [...prevMessages, message]);
}
}
})
})
}, [])
See the React docs for more info: https://reactjs.org/docs/hooks-reference.html#functional-updates