Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React hooks: get state of useState inside a listener

I have this inside my component:

const [ pendingMessages, setPendingMessages ] = React.useState([]);

React.useEffect(function() {
    ref.current.addEventListener('send-message', onSendMessage);
    return function() {
      ref.current.removeEventListener('send-message', onSendMessage);
    };
  }, []);

function onSendMessage(event) {
  const newMessage = event.message;
  console.log('Here not up to date :(', pendingMessages);
  setPendingMessages([ ...pendingMessages, newMessage ]);
}

The problem is that pendingMessages is not up to date inside the listener because it's not inside the render. It's already attached. Any ideas how can I resolve this?

Thanks!

like image 825
Mati Tucci Avatar asked Feb 05 '19 06:02

Mati Tucci


1 Answers

The problem is because of a close that is formed when the effect is run. Since you set the useEffect to run only on initial mount, it gets the value of pendingMessages from the closure that is formed when it is declared and hence even if the the pendingMessages updates, pendingMessages inside onSendMessage will refer to the same value that was present initially.

Since you do not want to access the value in onSendMessage and just update the state based on previous value, you could simply use the callback pattern of setter

const [ pendingMessages, setPendingMessages ] = React.useState([]);

React.useEffect(function() {
    ref.current.addEventListener('send-message', onSendMessage);
    return function() {
      ref.current.removeEventListener('send-message', onSendMessage);
    };
  }, []);

function onSendMessage(event) {
  const newMessage = event.message;
  setPendingMessages(prevState =>([ ...prevState, newMessage ]));
}
like image 96
Shubham Khatri Avatar answered Nov 18 '22 05:11

Shubham Khatri