Updated useState value not showing in another function

In the sample code var1 variable latest value is not accessible inside the event listener for ‘my_event’. setTimeout updates the var1 value to [‘a’,’b’] but when doSomething function is called the value in the function onMyEvent still prints the initial var1 value []

Any insight into the issue and fix will be very helpful. Thanks

Code sample

import { useEffect, useState } from 'react';

function App() {
  const [var1, setVar1] = useState([])

  const onMyEvent = (e)=>{
    console.log("Detail var1 in onMyEvent: ", var1)//var1 value still prints as [] and not ['a','b']
  }
  useEffect(()=>{
    document.addEventListener('my_event', onMyEvent);
    setTimeout(()=>setVar1(['a','b']),1000)
  },[])
  const doSomething = ()=>{
    document.dispatchEvent(new CustomEvent('my_event', { detail: 5 }));
  }
  return (
    <div className="App">
      <div>{var1.toString()}</div><br/>
      <button onClick={doSomething}>Show Data</button>
    </div>
  );
}

export default App;

Answer

You need to add var1 into the array of dependencies in useEffect. That way every time the variable var1 changes, what’s inside useEffect will be reevaluated.

Every time the var1 changes, it will create an event listener to your custom event for onMyEvent function with the correct value for var1. Also, to prevent creating multiple event listeners unintentionally, one can use the return function to unsubscribe to the event once the var1 changes again.

import { useEffect, useState } from 'react';

function App() {
  const [var1, setVar1] = useState([])

  const onMyEvent = (e)=>{
    console.log("Detail var1 in onMyEvent: ", var1)//var1 value still prints as [] and not ['a','b']
  }

  useEffect(()=>{
    document.addEventListener('my_event', onMyEvent);
    setTimeout(()=>setVar1(['a','b']),1000)
    return () => {
        document.removeEventListener('my_event', onMyEvent);
    } 
  },[var1])

  const doSomething = ()=>{
    document.dispatchEvent(new CustomEvent('my_event', { detail: 5 }));
  }

  return (
    <div className="App">
      <div>{var1.toString()}</div><br/>
      <button onClick={doSomething}>Show Data</button>
    </div>
  );
}

export default App;