skip to Main Content

So… when I do something like:

const [count, setCount] = React.useState(0);

// in something else now
setCount(5);

Now, I don’t really know when setCount is going to update… I can’t be sure. Obviously, the current solution is

React.useEffect(() => {
    // ... then do something
}, [count]);

but why not make setCount async?

// count might not be 5, but will definitely have updated.
setCount(5).then(count => {
    // ... then do something
})

This is a question about React’s hook’s API design. I am not asking about how I can achieve something, more why the library is built this way.

3

Answers


  1. That is a good look in, to the design. Well there are some reason why setState is not asynchronous. Based on my experience and perspective, it is mainly the performance optimization factor why the setState is not asynchronous in React.

    To understand this further lets say, when you call setState in React, the component is scheduled for a re-render but is not executed right away. Instead, it does the re-render at the conclusion of the cycle after batching all state modifications that take place within a single render cycle.

    Now if the setState were asynchronous, Each state change would start a new re-render cycle, which would be less effective. SetState may be made synchronous so that React can group together many state modifications and only need to re-render the component once.

    Ultimately, React’s design choice to make setState synchronous is a compromise between efficiency and complexity, and it has been successful in helping React components manage state.

    Login or Signup to reply.
  2. setState is actually not async in reality because an async function is expected to return a promise. But It does appear as async, because of something called batching of states i.e. The way in which react actually updates the state. If you want to understand it even deeply… learn about batching of states in react.

    Login or Signup to reply.
  3. React is fundamentally designed around writing declarative code, instead of imperative code.

    It’s not about time, it’s about dependencies.

    You are not supposed to ask "when setCount is going to update", you should not even think about code like "do this, and then do something else", you should only think about "the state should be this value now", and "state B depends on state A".

    I.e. your example

    setCount(5).then( count => { /* ...do something else */ } )
    

    says "as soon as this value is set, do something else…".

    That is imperative code, and thus violates the basic concepts of React (i.e. writing declarative code).

    declare:

    Instead you should declare what you want the state to be now.
    E.g. you should say "The variable count should be 5":

    setCount(5);
    

    dependencies:

    And then you specify dependencies, e.g. you might say somewhere else in your code "count items of my data should be displayed", so the items array depends on count, e.g.:

    const displayedItems = React.useMemo(
        () => data.filter( (_, index) => index < count ),
        [ count, data ]
    );
    

    side effects:

    If e.g. not enough data is available, you might use a side effect, aka. useEffect, that depends on count and the available data, and might fetch some additional data, e.g.:

    useEffect(
        () => {
            if( data.length < count ){
                fetchMoreData( count ).then( newData => {
                    setData( newData );
                });
            }
        },
        [ count, data ]
    );
    

    Links

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search