Skip to content

getState() hook proposal #14092

Description

@denysonique

useState() provided state value currently cannot be used in useEffect(fn, []) - (componentDidMount-like scenario) with asynchronous functions after state has been updated following the initial [] run.

Upon trying to give Hooks a try for a real world application I was initially confused with accessing state. Here is a little example what I tried to do:

constUserList=()=>{const[users,setUsers]=useState([])useEffect(()=>{constsocket=io('/dashboard')socket.on('user:connect',(user)=>{setUsers([...users,user])})socket.on('user:update',(user)=>{letnewUsers=users.map((u)=>u.id==user.id ? user : u)setUsers(newUsers)})},[])return(users.map(({id, email})=>(<trkey={id}><td>{id}</td><td>{email}</td></tr>)))}

Upon running this I instantly realised that inside the socket.on() handler the users initially obtained from useState() did not reflect the changes inflicted by setUsers() ran on socket.on('user:connect'). Passing [users] as the second argument of useEffect() wasn't an option as that would cause additional socket.on() binds. I became skeptical about Hooks for this use case and sadly thought this would be where my journey with using hooks instead of the class components would end.

Fortunately I then found a solution to this problem (with someone indirectly having helped me by accident in the reactflux channel) by using an updater function with setState() which made it all work:

socket.on('user:update',(user)=>{setUsers(users=>users.map((u)=>u.id==user.id ? user : u))})

The setState() problem was solved, but I am now wondering that if I will ever need to access state outside of an updater function, i.e. to just reply to a WebSocket message with some value from the state I will be unable to do so and this will force me and other users to revert to class components for such cases.

I therefore would like to suggest that a getState() hook would be an ideal solution to this problem.




Here is another mini example demonstrating the problem in a more concise manner:

constHooksComponent=()=>{const[value,setValue]=useState({val: 0});useEffect(()=>{setTimeout(()=>setValue({val: 10}),100)setTimeout(()=>console.log('value: ',value.val),200)},[]);}//console.log output: 0 instead of 10

And here is one with a proposed solution:

constHooksComponent=()=>{const[state,setState,getState]=useState({val: 0});useEffect(()=>{setTimeout(()=>setState({val: 10}),100)setTimeout(()=>{getState(state=>{console.log('value: ',state.val)})},200)},[])

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions