Tom Haines
Tom Haines

Reputation: 123

React hooks state is undefined when updating

I have a simple React Hooks component. When I try and update the lightState using the setLightState function it returns undefined for the current state. Accessing the state inside the return body works fine.

const MainControl = () => {
  const [lightState, setLightState] = useState()
  const [lightChan, setLightChan] = useState()

  const updateLight = (newState) => {
    setLightState({...lightState, ...newState})
  }

  useEffect(() => {

    socket.connect()
    let chan = socket.channel("lights:dioder")

    chan.join().receive("ok", (response) => {
      setLightState(response)
      setLightChan(chan)
    })

    chan.on("light_colour", (resp) => {
      updateLight(resp)
    })

    return () => {
      chan.leave()
    }
  }, [])

  if (!lightChan) return <h2>Loading...</h2>

  return (
     <h2>Lights are currently {lightState.on ? "on" : "off"}</h2>
  )
}

The updateLight function reads lightState as undefined, but the return body does not? I think this may only be true on the first render but I'm not sure.

Thanks

Upvotes: 0

Views: 9564

Answers (2)

Tony Nguyen
Tony Nguyen

Reputation: 3488

updateLight(resp) is use in the callback function of chan.on, when you declare chan.on the lightState is undefined. So whenever callback of chan.on is trigger the value of setLightState is undefined (Closure of JS). If you want to set new state using previous state value, you need to pass a function to setLightState

setLightState(prevLightState => ({...prevLightState, ...newState}))

Upvotes: 1

mindlis
mindlis

Reputation: 1677

When you're initializing your state with useState you aren't setting an initial value for lightState. You can initialize it as an empty object useState({}) and it should work.

Also see using useCallback to update function params when dependent variables change.

See declaring a state variable and useCallback for more details.

Upvotes: 0

Related Questions