Search code examples
javascriptreactjsclosuresreact-hookslexical-closures

React setstate not merging the old state into the new state


according to many examples, this should work:

const [_timeseries, $timeseries] = useState({hi:'lol'})

useEffect(() => {

socket.on('plot', e => {
 let keyname = Object.keys(e)[0]
 $timeseries({..._timeseries, [keyname] : value)})
}

}, [])

console.log(_timeseries) // here results in the initial state, not the set state

The first time it merges, it works. But once a new event with another keyname enters, it replaces the whole thing again. Instead of adding a new key with [keyname], the old [keyname] is being replaced.


Solution

  • The problem here is closures.

    The callback assigned to the useEffect closes the initial value of _timeseries in it's the lexical scope and it never updated.

    To fix it, you need to use the functional useState which uses the most updated state within its callback:

    const [_timeseries, $timeseries] = useState({hi:'lol'})
    
    useEffect(() => {
    socket.on('plot', e => {
     let keyname = Object.keys(e)[0]
     $timeseries(timeSeries => {...timeseries, [keyname] : value)})
    }
    
    }, [])