简体   繁体   中英

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.

The useState hook gives you a function which replaces the state entirely with a new value (doesn't merge it): https://reactjs.org/docs/hooks-state.html

However, unlike this.setState in a class, updating a state variable always replaces it instead of merging it.

You can use setState with a function and merge it yourself:

$timeseries((old) => ({...old, [keyname] : value)}))

If you use it without a function it might have the old values (because you don't specify it as a dependency of useEffect)

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)})
}

}, [])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM