React useState Hook
Managing state in functional components
📊 What is useState?
useState is a React Hook that lets you add state to functional components. It returns an array with the current state value and a function to update it, making state management simple and intuitive.
import { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return <p>Count: {count}</p>;
}
useState Key Concepts
Initial State
Set starting value for state
const [count, setCount] = useState(0);
State Update
Change state with setter function
setCount(count + 1);
Multiple States
Use multiple useState hooks
const [name, setName] = useState('');
const [age, setAge] = useState(0);
Any Data Type
Store strings, numbers, objects, arrays
const [user, setUser] = useState({});
🔹 Basic useState Example
The simplest use of useState is to manage a single value like a counter. The hook returns the current value and a function to update it.
import { useState } from 'react';
function Counter() {
// Declare state variable 'count' with initial value 0
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
Output:
You clicked 0 times
🔹 useState with Strings
You can use useState to manage text input values. This is commonly used for forms where users type information like names or messages.
import { useState } from 'react';
function NameInput() {
const [name, setName] = useState('');
return (
<div>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter your name"
/>
<p>Hello, {name || 'stranger'}!</p>
</div>
);
}
Output:
Hello, stranger!
🔹 useState with Objects
When managing multiple related values, you can store them in an object. Remember to spread the previous state when updating to avoid losing other properties.
import { useState } from 'react';
function UserForm() {
const [user, setUser] = useState({
name: '',
email: '',
age: 0
});
const updateName = (e) => {
setUser({ ...user, name: e.target.value });
};
return (
<div>
<input
value={user.name}
onChange={updateName}
placeholder="Name"
/>
<p>Name: {user.name}</p>
</div>
);
}
Output:
Name:
🔹 useState with Arrays
Arrays are perfect for managing lists of items. You can add, remove, or update items using array methods combined with the state setter function.
import { useState } from 'react';
function TodoList() {
const [todos, setTodos] = useState(['Learn React', 'Build app']);
const [input, setInput] = useState('');
const addTodo = () => {
if (input.trim()) {
setTodos([...todos, input]);
setInput('');
}
};
return (
<div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="New todo"
/>
<button onClick={addTodo}>Add</button>
<ul>
{todos.map((todo, index) => (
<li key={index}>{todo}</li>
))}
</ul>
</div>
);
}
Output:
- Learn React
- Build app
🔹 Functional Updates
When the new state depends on the previous state, use a function inside the setter. This ensures you always work with the latest state value, especially important for rapid updates.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
// ❌ Not recommended for dependent updates
const incrementBad = () => {
setCount(count + 1);
};
// ✅ Recommended - uses previous state
const incrementGood = () => {
setCount(prevCount => prevCount + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={incrementGood}>
Increment
</button>
</div>
);
}
Output:
Count: 0
🔹 useState Best Practices
✅ Do's:
- Descriptive names: Use clear names like [isLoading, setIsLoading]
- Functional updates: Use prevState when new state depends on old
- Split state: Use multiple useState for unrelated data
- Initialize properly: Set appropriate initial values
❌ Don'ts:
- Don't mutate state: Always create new objects/arrays
- Don't call in loops: Keep useState at component top level
- Don't overuse objects: Split into multiple states when possible