useState β Getting Started with React State Management
After completing this topic, you will:
Understand how to create and update state using useState, and how re-rendering works.
Regular variables won't work
function Counter() {
let count = 0;
function handleClick() {
count += 1;
console.log(count); // 1, 2, 3... increments
}
return <button onClick={handleClick}>{count}</button>;
// Always displays 0
}count increments, but the screen doesn't update. React doesn't detect changes in regular variables. To update the screen, you need to tell React that the "state has changed."
useState
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
);
}useState(0) returns two things:
count: The current state valuesetCount: A function to change the state
Calling setCount causes React to re-render the component. The screen is redrawn with the new count value.
State updates are asynchronous
function handleClick() {
setCount(count + 1);
console.log(count); // Still the previous value!
}Even after calling setCount, count doesn't change immediately. The new value will be reflected in the next render.
When updating based on the previous value, use functional updates:
setCount(prev => prev + 1);prev contains the current, latest value. This is accurate even with multiple consecutive calls:
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);
// count increases by 3Object and array state
const [user, setUser] = useState({ name: "Alice", age: 25 });
// Bad example: direct modification
user.age = 26; // React won't detect the change
setUser(user); // Same reference, so no re-render
// Good example: create a new object
setUser({ ...user, age: 26 });React checks if the reference has changed. If you modify the existing object, the reference remains the same, and React won't detect the change. You must create a new object using the spread operator.
Arrays are the same:
const [items, setItems] = useState(["a", "b"]);
// Add
setItems([...items, "c"]);
// Delete
setItems(items.filter(item => item !== "b"));
// Modify
setItems(items.map(item => item === "a" ? "A" : item));Don't use methods that modify the original array, like push or splice.
Multiple useState calls
const [name, setName] = useState("");
const [age, setAge] = useState(0);
const [isActive, setIsActive] = useState(false);Declare separate states for unrelated values. You can also group values that always change together into a single object.
Key takeaways
useStateadds state to a React component, and callingsetStatecauses a re-render. State updates are asynchronous, so use functional (prev => ...) updates when updating based on the previous value. For object/array state, create new ones instead of modifying the original.