100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
React

The useState Hook

Master useState, the Hook that adds local state to function components, including initial values, updater functions, and functional updates.

Hooks FundamentalsBeginner10 min readJul 8, 2026
Analogies

Introduction

useState is the most commonly used React Hook. It lets a function component declare a piece of local state that persists across re-renders. Calling useState returns an array with two elements: the current state value and a function to update it. When the updater function is called, React re-renders the component with the new state value, similar to how this.setState works in class components but scoped to a single piece of state.

🏏

Cricket analogy: useState is like a single entry on the scoreboard for 'current batsman's score' — calling the update function is like the scorer signaling a new run tally, which redraws just that scoreboard segment, unlike the old class-component style of updating the whole board object at once.

Syntax

jsx
const [state, setState] = useState(initialValue);

// Example
function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

Explanation

The argument passed to useState becomes the state's initial value on the first render only; on subsequent renders, that argument is ignored and React returns the current stored value. If computing the initial value is expensive, you can pass a function instead (lazy initialization), e.g. useState(() => expensiveComputation()), and React will call it only once. The setter function can accept either a new value directly, or an updater function of the form (prevState) => newState. The functional form is important when the new state depends on the previous state, especially inside closures like event handlers, timers, or effects, because it always receives the most current state rather than a possibly stale value captured by the closure. React also batches multiple setState calls that occur within the same event handler into a single re-render for performance. Unlike this.setState in classes, useState's setter replaces the state entirely rather than merging it, so when state is an object you must spread the previous object manually to keep unrelated fields.

🏏

Cricket analogy: The opening pitch report is only read once at the start of the innings — recalculating it every over would be wasteful, so a lazy initializer computes it once, like a groundskeeper's expensive pitch analysis done only at toss time. Using the functional updater form when adding runs from three quick boundaries in one over ensures each addition reads the true current total rather than a stale total remembered from the over's start, and because useState replaces rather than merges, you must carry forward the wickets and overs fields manually when updating just the runs.

Example

jsx
function ProfileForm() {
  const [user, setUser] = useState({ name: '', age: 0 });

  function updateName(newName) {
    // Must spread previous state since setState replaces, not merges
    setUser(prev => ({ ...prev, name: newName }));
  }

  function incrementAgeThreeTimes() {
    // Functional updates guarantee correctness even when called multiple times
    setUser(prev => ({ ...prev, age: prev.age + 1 }));
    setUser(prev => ({ ...prev, age: prev.age + 1 }));
    setUser(prev => ({ ...prev, age: prev.age + 1 }));
  }

  return (
    <div>
      <input value={user.name} onChange={e => updateName(e.target.value)} />
      <p>Age: {user.age}</p>
      <button onClick={incrementAgeThreeTimes}>+3 years</button>
    </div>
  );
}

Output

Typing into the input updates only the name field while preserving age, because the functional updater spreads the previous state. Clicking '+3 years' correctly increases age by exactly 3, because each functional update reads the latest pending state rather than a stale snapshot captured when incrementAgeThreeTimes was defined. If a plain value form (setUser({...user, age: user.age + 1})) were called three times in a row, all three calls would reference the same stale 'user' from the closure and age would only increase by 1.

🏏

Cricket analogy: Editing a player's nickname on the roster updates only that field while their runs-scored tally stays intact, because the update spreads the previous player object. Tapping '+3 overs bowled' three times correctly adds 3 total because each functional update reads the latest pending count; if a plain value form referencing the same stale 'overs' variable were used three times, the tally would only increase by 1.

Key Takeaways

  • useState(initialValue) returns [currentValue, setterFunction] and is used for local component state.
  • The initial value argument is only used on the very first render.
  • Use lazy initialization (useState(() => compute())) for expensive initial state computations.
  • The setter can take a new value or an updater function (prevState) => newState; prefer the functional form when new state depends on old state.
  • useState replaces state rather than merging it, so object/array state must be manually spread to preserve unrelated fields.
  • Multiple setState calls in the same event handler are batched into a single re-render.

Practice what you learned

Was this page helpful?

Topics covered

#React#ReactJsStudyNotes#WebDevelopment#TheUseStateHook#UseState#Hook#Syntax#Explanation#StudyNotes#SkillVeris