React components often need to remember and change data - like a button click count, form input values, or whether a modal is open. React's useState hook makes this possible.
What is State?
State is data that can change over time in your component. When state changes, React automatically re-renders your component with the new values.
Think of state like a variable that React watches. When it changes, React updates what users see.
// This won't work - regular variables don't trigger re-renders
function Counter() {
let count = 0;
const increment = () => {
count = count + 1; // Changes the variable but doesn't update the UI
};
return <button onClick={increment}>{count}</button>; // Always shows 0
}
Your First useState Example:
import { useState } from 'react';
function Counter() {
// 1. Declaring the state variable: count holds the current value.
// 2. useState takes as a parameter the initial value, in this case is 0.
const [count, setCount] = useState(0);
// 2. Creating the update function. setCount changes the state.
const increment = () => {
setCount(count + 1); // Updates state AND triggers re-render
};
return <button onClick={increment}>{count}</button>; // Shows current count
}
The useState pattern
The naming pattern is [value, setValue] - you can name them anything:
// Setting a name as state variable, initial value is an empty string
const [name, setName] = useState('');
// Setting a isOpen flag as a state variable, initial value is false
const [isOpen, setIsOpen] = useState(false);
// Setting items as a state variable, initial value is an empty array
const [items, setItems] = useState([]);
Practical Examples
An Input field
import { useState} from 'react';
export default function NameForm() {
const [name, setName] = useState('');
return (
<div>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter your name"
/>
<p>Hello, {name}!</p>
</div>
);
}
A Toggle button
import { useState} from 'react';
export default function ToggleButton() {
const [isOn, setIsOn] = useState(false);
return (
<button onClick={() => setIsOn(!isOn)}>
{isOn ? 'ON' : 'OFF'}
</button>
);
}
Shopping List
import { useState} from 'react';
export default function ShoppingList() {
const [items, setItems] = useState([]);
const [newItem, setNewItem] = useState('');
const addItem = () => {
setItems([...items, newItem]);
setNewItem('');
};
return (
<div>
<input
value={newItem}
onChange={(e) => setNewItem(e.target.value)}
placeholder="Add item"
/>
<button onClick={addItem}>Add</button>
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
Important Rules
1. State updates are asynchronous: React batches state updates for performance. The new value isn't available immediately after calling the setter.
const handleClick = () => {
setCount(count + 1);
console.log(count); // Still shows the old value
};
2. Don't mutate state directly: Always use the setter function. React won't detect changes to objects or arrays if you modify them directly.
// Wrong - mutating directly
const addItem = () => {
items.push(newItem); // React won't detect this change
setItems(items);
};
// Right - creating new array
const addItem = () => {
setItems([...items, newItem]); // React detects this change
};
3. Initial state only runs once: The value you pass to useState is only used on the first render.
const [count, setCount] = useState(Math.random()); // Only calculated once
When to Use State
Use useState when:
- Data changes in response to user actions
- You need to show different content based on conditions
- Values need to persist between renders
- You're handling form inputs
Don't use state for:
- Values that never change
- Data that can be calculated from other state
- Values only used during a single render
State is the foundation of interactive React applications. Master useState and you'll be able to build dynamic, responsive user interfaces.
Now that you understand basic state management, you're ready to learn about more advanced patterns like functional updates, which help avoid common bugs when updating state based on previous values.