1

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.

Dennis Vash
  • 50,196
  • 9
  • 100
  • 118

2 Answers2

1

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

}, [])
Dennis Vash
  • 50,196
  • 9
  • 100
  • 118
0

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)

tudor.gergely
  • 4,800
  • 1
  • 16
  • 22
  • yes, thats what i'm doing. the merge works, its just that after the second time it stops working. –  Mar 24 '20 at 10:43
  • @BTj84VvNNL2gh9GC you are not using a function inside $timeseries, you are using the variable _timeseries – tudor.gergely Mar 24 '20 at 10:43
  • You should use a function otherwise you might endup with wrong values – tudor.gergely Mar 24 '20 at 10:44
  • so that would work without a function if it wouldn't be for the useEffect dependecy missing? –  Mar 24 '20 at 10:47
  • 1
    yes, but in your case I would use a function, otherwise you would have to unsubscribe and resubscribe to the socket. – tudor.gergely Mar 24 '20 at 10:48
  • thanks it worked with the function.. it's an unintuitive behavior for me.. how is it interacting with the useffect dependency? –  Mar 24 '20 at 10:49
  • I recommend you read a bit about hooks here: https://reactjs.org/docs/hooks-effect.html and https://dev.to/dan_abramov/making-sense-of-react-hooks-2eib . The main idea is that if you don't specify external values inside the dependencies array and those values update then you end up using old values in useEffect. Using a function inside setState will avoid this because it always passes the right value to that function. – tudor.gergely Mar 24 '20 at 10:53
  • If you think this answered helped you (or any answer on any question you will ask) you can mark it as approved from the leftside. – tudor.gergely Mar 24 '20 at 10:54
  • @BTj84VvNNL2gh9GC: *"how is it interacting with the useffect dependency?"* It's not. It's a feature of (the setter returned by) `useState`. If you pass a function the setter it will always pass the current value to it. – Felix Kling Mar 24 '20 at 11:01