Skip to content
beginnerPhase 36 · React

State

Manage component state with useState, understand state updates, and immutability.

45m
0 problems
Topic Progress0%

useState Hook

useState Hook

The useState hook lets you add state to functional components.

Basic Usage

import { useState } from "react";

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

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

How useState Works

  • useState(0) initializes state with 0
  • Returns [count, setCount]:
    • count: current state value
    • setCount: function to update state
  • Calling setCount triggers re-render

Multiple State Variables

function Form() {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [age, setAge] = useState(0);

  return (
    <form>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      <input type="number" value={age} onChange={(e) => setAge(Number(e.target.value))} />
    </form>
  );
}

State with Objects

function UserForm() {
  const [user, setUser] = useState({
    name: "",
    email: "",
    age: 0
  });

  // Update single property
  const updateName = (name) => {
    setUser({ ...user, name });
  };

  return (
    <form>
      <input value={user.name} onChange={(e) => updateName(e.target.value)} />
    </form>
  );
}

State Updates

State Updates

State Updates are Asynchronous

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

  const handleClick = () => {
    setCount(count + 1);
    console.log(count); // Still 0! Not updated yet
  };

  return (
    <div>
      <p>{count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}

State Batching

function Form() {
  const [name, setName] = useState("");
  const [age, setAge] = useState(0);

  const handleSubmit = () => {
    // These are batched into one re-render
    setName("Alice");
    setAge(30);
  };
}

Functional Updates

When new state depends on old state, use a function:

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

  // Bad: may use stale value
  const increment = () => {
    setCount(count + 1);
    setCount(count + 1); // Only adds 1!
  };

  // Good: always uses latest value
  const increment = () => {
    setCount(prev => prev + 1);
    setCount(prev => prev + 1); // Adds 2!
  };
}

Immutable State

Immutable State

Why Immutable?

React uses reference equality to detect changes. Mutating objects won't trigger re-renders.

// Wrong: mutation
function TodoApp() {
  const [todos, setTodos] = useState([{ text: "Learn React", done: false }]);

  const toggle = (index) => {
    todos[index].done = true; // Mutation!
    setTodos(todos); // No re-render!
  };
}

// Correct: immutable update
const toggle = (index) => {
  const newTodos = todos.map((todo, i) =>
    i === index ? { ...todo, done: true } : todo
  );
  setTodos(newTodos); // Triggers re-render
};

Immutable Patterns

// Adding to array
setTodos([...todos, newTodo]);

// Removing from array
setTodos(todos.filter(t => t.id !== id));

// Updating item in array
setTodos(todos.map(t => t.id === id ? { ...t, done: true } : t));

// Updating object property
setUser({ ...user, name: "New Name" });

// Removing property
const { password, ...rest } = user;
setUser(rest);

spread Operator

// Shallow copy object
const newUser = { ...user, name: "Alice" };

// Shallow copy array
const newTodos = [...todos, newTodo];

// Nested updates (not recommended - use libraries)
const newState = {
  ...state,
  user: {
    ...state.user,
    name: "Alice"
  }
};

Practice Problems

0/3solved
Build State Component

Create a reusable React component implementing State. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
State Testing

Write unit and integration tests for State using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
State Performance

Optimize State for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What does useState return?

Question 1 options

2. Are state updates synchronous?

Question 2 options

3. Why should state be immutable?

Question 3 options

4. When should you use functional updates?

Question 4 options

Flashcards

Question

What does useState do?

Answer

Adds state to functional components

Question

What does useState return?

Answer

An array with [state, setState]

Question

Why use functional updates?

Answer

When new state depends on previous state

Question

What is immutable state?

Answer

Creating new objects instead of mutating existing ones

Question

What is State?

Answer

State is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.useState adds state to functional components
  • 2.State updates are asynchronous and batched
  • 3.Use functional updates when new state depends on old
  • 4.State must be immutable for React to detect changes
  • 5.Use spread operator for immutable updates

Interview Tips

  • Explain why state updates are asynchronous
  • Show immutable state update patterns
  • Demonstrate when to use functional updates

Cheat Sheet

Cheat Sheet

Basic useState

const [count, setCount] = useState(0);
setCount(count + 1);

Functional Update

setCount(prev => prev + 1);

Immutable Patterns

// Add
setTodos([...todos, newTodo]);
// Remove
setTodos(todos.filter(t => t.id !== id));
// Update
setTodos(todos.map(t => t.id === id ? {...t, done: true} : t));
// Object
setUser({ ...user, name: "Alice" });