Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
State  ›  Lesson

useState — Memory for a Component

useState 16 minuseState gives a component a value that survives between renders plus a setter that replaces the value and triggers a re-render; each render sees a fixed snapshot.

useState — Memory for a Component

The like button on each book should count clicks. A plain let likes = 0 inside the component will not work: every render calls the function again and likes starts from zero. And even if you changed it, React would not know to redraw. A component needs memory that survives renders and tells React when it changes. That is state.

The rule

State is a snapshot; set it to a new value, never change it.

import { useState } from 'react';

function LikeButton() {
  const [likes, setLikes] = useState(0);

  return (
    <button onClick={() => setLikes(likes + 1)}>
      ♥ {likes}
    </button>
  );
}

useState(0) returns a pair: the current value and a setter. The 0 is only used on the first render; after that React remembers the value. Calling the setter stores a new value and triggers a re-render, where likes holds the new number.

A snapshot. Within one render, likes is a constant. Calling setLikes does not change the variable you are holding; it schedules the next render. So this adds only 1:

setLikes(likes + 1); // 0 + 1
setLikes(likes + 1); // still 0 + 1
setLikes(likes + 1); // still 0 + 1

When the next value depends on the previous one, pass an updater function. React feeds each one the latest pending value:

setLikes(l => l + 1); // three of these add 3

Set a new value, never change it. For objects and arrays, make a new copy with the change:

setBooks([...books, newBook]);                         // add
setBooks(books.filter(b => b.id !== id));               // remove
setBooks(books.map(b => b.id === id ? { ...b, read: true } : b)); // edit

books.push(newBook) changes the old array in place; React sees the same array and may skip the update.

Props or state? Props are handed to you by a parent and are read-only. State is kept by the component itself and changes over time. Each <LikeButton /> on the page has its own separate likes. If two components need the same changing value, move the state up to their closest shared parent and pass it down as props.

The shortcut

Before writing a setter, ask two questions: "Does the new value depend on the old one?" If yes, use an updater. "Is it an object or array?" If yes, build a new one.

Clicking "+3" onceStep 1 of 4
  1. Read the snapshot

    This render has likes = 5.

Drills

Answer fast — trust the rule.

quick drill

With likes = 2, a handler calls setLikes(likes + 1) twice. What does the next render show?

quick drill

With likes = 2, a handler calls setLikes(l => l + 1) twice. What does the next render show?

quick drill

Which correctly adds newBook to books state?

quick drill

Right after setLikes(10), the next line logs likes. What does it print if likes was 4?

quick drill

Two sibling components must show the same changing count. Where should the state live?

Remember

  • State is a snapshot; set it to a new value, never change it.
  • Depends on the old value? Use an updater. Object or array? Build a new one.
  • Trap: setX(x + 1) repeated, and push on state arrays.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainWhy only +1?

A like button's handler runs setLikes(likes + 1) three times in a row, hoping to add 3, but the count only goes up by 1. Explain why, how to fix it, and how you would add a new book to a books array held in state.