Skip to content

useState Hook

  • useState hook is deferred (scheduled)
  • Stores state for a component
  • Triggers re-render when state changes
  • React tracks hooks by order (index), which is why hooks must be called in the same order on every render.

useState Synchronous or Asynchronous

  • The useState hook is synchronous, but state updates are asynchronous.

  • When you call useState(), it runs synchronously and returns the state variable and setter function as tuple.This happens immediately during rendering

  • However, the state update function (setState) is asynchronous in the sense that it doesn't update the state immediately. React batches updates and applies them before the next render.

Closures and Batching

js
setCount(count+1);
setCount(count+1);
setCount(count+1);
setCount(count+1);
setCount(count+1);
Expected : +5
Actual : +1
  • Root cause:
    • Closure: Functions in JavaScript capture variables from their lexical scope.

    • React batching: React groups multiple state updates into one transfer. - React internally sees this:

      ```js
      setCount(1);
      setCount(1);
      setCount(1);
      setCount(1);
      setCount(1)
      ```
      
  • Correct Approach
js
setCount(prev=>prev+1);
setCount(prev=>prev+1);
setCount(prev=>prev+1);
setCount(prev=>prev+1);
setCount(prev=>prev+1);

Using Objects with useState

js
const [state,setState] = useState({
    name : "Chandan",
    age : 21
})

setState({age:state.age+1})

Output :

state : {
    name : undefined
    age : 22
}
  • This happens because useState does not merge objects; it replaces them.

  • Similarly for arrays:

js

const [items, setItems] = useState(["apple", "banana"]);

setItems(["cherry"]);// items = ["cherry"]

setItems([...items, "cherry"]);

// Removing
setItems(items.filter(item => item !== "banana"));

// Updating
setItems(items.map(item => item === "apple" ? "mango" : item));
  • Correct Approach
js
setState({...state,age:state.age+1})

Lazy Initialization

  • The initial state is computed only once (on the first render).
js
const [count, setCount] = useState(() => expensiveFunction());
const [state,setState] = useState(()=>(
    {
        name: getValue(),
        age:21
    }
))