React Hook set value not working inside EventSource.onmessage

Viewed 301

I'll show below the simplified version of the SSE part of my React project.

For some reason, I am not being able to change the state of a variable inside the EventSource.onmessage function.

function App() {
  const [variable, setVariable] = useState("qwerty");

  const mockFunc = () => {
    let eventSource = new EventSource("http://localhost:5000/stream");
    eventSource.onmessage = function (e) {
      console.log("variable:", variable);
      setVariable("abc");
    };
  };


  useEffect(() => {
    console.log("UseEffect: ",variable);
  }, [variable]);



return (
        <div>
          <button onClick={mockFunc}>updateVariable</button>
       </div>
      );
    }
    
    export default App;

From the Flask side I am sending a message every 5 seconds and successfully receiving it on the React side. But, for some reason, setVariable is not working properly, since the value of variable is not actually being set. Here are the resulting logs from the program.

variable: qwerty

UseEffect: abc

variable: qwerty

variable: qwerty

variable: qwerty

.... indefinetely

Which means, setVariable not only does not trigger useEffect more than once, it actually resets the value to the original setState (?).

This does not make any sense to me. If I make a button that changes the variable value with setVariable it works fine, so I don't get why it's not working this way.

Thanks in advance

1 Answers

It's a stale enclosure over the variable state value in the onmessage callback handler.

You could use a React ref and an useEffect hook to cache the variable state value and access the cached value in the onmessage callback.

Example:

function App() {
  const [variable, setVariable] = useState("qwerty");

  const variableRef = useRef();

  useEffect(() => {
    variableRef.current = variable;
  }, [variable]);

  const mockFunc = () => {
    let eventSource = new EventSource("http://localhost:5000/stream");
    eventSource.onmessage = function (e) {
      console.log("variable:", variableRef.current);
      setVariable("abc");
    };
  };

  useEffect(() => {
    console.log("UseEffect: ", variable);
  }, [variable]);

  return (
    <div className="App">
      <button onClick={mockFunc}>updateVariable</button>
    </div>
  );
}

Edit react-hook-set-value-not-working-inside-eventsource-onmessage

Log output:

enter image description here

Related