🔥 0
0
Lesson 4 of 9 20 min +100 XP

State with useState

State is what makes React components interactive. While props are passed from parent to child (and are read-only), state is managed within a component and can change over time.

What is State?

State is data that:

  • Belongs to a specific component
  • Can change over time (usually in response to user actions)
  • Causes the component to re-render when it changes

Think of state as a component's memory - it remembers things between renders.

The useState Hook

React provides the useState hook to add state to functional components:

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>
  );
}

Breaking it Down

const [count, setCount] = useState(0);
  • useState(0) - Initialize state with value 0
  • count - The current state value
  • setCount - Function to update the state
  • This uses array destructuring to get both values

Updating State

Basic Updates

// Set to a specific value
setCount(5);

// Set based on current value
setCount(count + 1);

Functional Updates

When the new state depends on the previous state, use a function:

// ✅ Correct - uses functional update
setCount(prevCount => prevCount + 1);

// ❌ Risky - might use stale value
setCount(count + 1);

This is especially important when updates might be batched or when updating state multiple times quickly.

State with Different Data Types

Strings

const [name, setName] = useState('');

<input
  value={name}
  onChange={(e) => setName(e.target.value)}
/>

Booleans

const [isVisible, setIsVisible] = useState(false);

<button onClick={() => setIsVisible(!isVisible)}>
  Toggle
</button>

Objects

const [user, setUser] = useState({ name: '', email: '' });

// ✅ Correct - spread existing properties
setUser({ ...user, name: 'Alice' });

// ❌ Wrong - loses the email property
setUser({ name: 'Alice' });

Arrays

const [items, setItems] = useState([]);

// Add item
setItems([...items, newItem]);

// Remove item
setItems(items.filter(item => item.id !== idToRemove));

// Update item
setItems(items.map(item =>
  item.id === id ? { ...item, done: true } : item
));

Multiple State Variables

You can use useState multiple times in a component:

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

  // Each has its own state and setter
}

State vs Props

PropsState
Passed from parentManaged within component
Read-onlyCan be changed
Component can't change themComponent controls them

Common Mistakes

1. Mutating State Directly

// ❌ Wrong
user.name = 'Bob';
setUser(user);

// ✅ Correct
setUser({ ...user, name: 'Bob' });

2. Forgetting State is Asynchronous

setCount(count + 1);
console.log(count); // Still shows old value!

// State updates are scheduled, not immediate

3. Using Objects When Separate Values Work

// Consider if these really need to be together
const [formData, setFormData] = useState({ name: '', email: '' });

// vs separate, simpler state
const [name, setName] = useState('');
const [email, setEmail] = useState('');

Key Takeaways

  • State is a component's memory that persists across renders
  • useState returns [value, setter]
  • Never mutate state directly - always use the setter
  • Use functional updates when new state depends on old state
  • State updates trigger re-renders

🧠 Quick Quiz

Test your understanding of this lesson.

1

What does useState return?

2

Why shouldn't you modify state directly?

3

When updating state based on the previous value, what should you use?

Building Components