React Tutorial menu

React useState Hook

State is data that a component remembers and that can change over time. The useState hook adds state to a function component.

What is a Hook?

Hooks are special functions whose names start with use. They let function components use React features such as state. You import them from react.

Two rules for all hooks:

  • Call hooks only at the top level of a component, not inside if, loops or nested functions
  • Call hooks only inside React components or your own custom hooks

Your First State

Example

jsx
import { useState } from "react";

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

  return (
    <div>
      <p>Cups of chai today: {count}</p>
      <button onClick={() => setCount(count + 1)}>Add one</button>
    </div>
  );
}
Output
Cups of chai today: 0
(after 3 clicks)
Cups of chai today: 3

useState(0) returns an array with two things, which we destructure:

PartMeaning
countThe current value (starts at 0)
setCountA function to change the value
0The initial value, used only on the first render

Why Not a Normal Variable?

A normal variable is reset every time the component runs, and changing it does not tell React to update the screen. Calling the setter (setCount) does two things: it stores the new value and asks React to re-render the component with it.

State Updates Are Not Immediate

After you call the setter, the variable keeps its old value until the next render.

Example

jsx
function handleClick() {
  setCount(count + 1);
  console.log(count); // still the old value
}

If the new value depends on the old one, and you update more than once, use the updater function form:

Example

jsx
function addThree() {
  setCount((c) => c + 1);
  setCount((c) => c + 1);
  setCount((c) => c + 1);
}

Each updater receives the latest value, so the count really goes up by 3. With setCount(count + 1) three times, it would go up by only 1.

Several State Variables

A component can have as many state variables as it needs:

Example

jsx
function LightSwitch() {
  const [isOn, setIsOn] = useState(false);
  const [room, setRoom] = useState("Bedroom");

  return (
    <div>
      <p>{room} light is {isOn ? "ON" : "OFF"}</p>
      <button onClick={() => setIsOn(!isOn)}>Toggle</button>
      <button onClick={() => setRoom("Kitchen")}>Go to kitchen</button>
    </div>
  );
}

Objects in State

Never change a state object directly. Create a new object with the spread operator ... and change only what you need.

Example

jsx
function Profile() {
  const [student, setStudent] = useState({ name: "Ali", city: "Karachi", age: 19 });

  function birthday() {
    setStudent({ ...student, age: student.age + 1 });
  }

  return (
    <div>
      <p>{student.name} from {student.city} is {student.age}</p>
      <button onClick={birthday}>Happy birthday!</button>
    </div>
  );
}
Output
Ali from Karachi is 19
(after click)
Ali from Karachi is 20

Arrays in State

The same idea applies to arrays. Use methods that return a new array.

TaskWrite
Add an itemsetItems([...items, newItem])
Remove an itemsetItems(items.filter((i) => i.id !== id))
Change an itemsetItems(items.map((i) => (i.id === id ? { ...i, done: true } : i)))

Avoid push, splice or assigning items[0] = .... These change the old array, and React may not notice.

Example

jsx
function TaskList() {
  const [tasks, setTasks] = useState(["Revise CSS"]);

  return (
    <div>
      <button onClick={() => setTasks([...tasks, "Practise JavaScript"])}>Add task</button>
      <ul>
        {tasks.map((t) => (
          <li key={t}>{t}</li>
        ))}
      </ul>
    </div>
  );
}

If two sibling components need the same state, move the state up to their common parent and pass it down as props. This is called lifting state up.

Exercise

Exercise

What does calling setCount(5) do?

Learn React with a teacher

Join the Full Stack Development course at Workownix, online or in Orangi Town, Karachi, and get a certificate.

See the course Ask on WhatsApp