React Hooks: useState and useEffect Explained
Essential hooks for modern React development
React Hooks revolutionized function components by providing state and lifecycle features previously exclusive to class components. Understanding these two fundamental hooks is essential for modern React development.
useState: Managing Component State
useState adds state to function 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>
);
}
Key points:
- Returns array: [currentValue, updaterFunction]
- Initial value passed to
useState() - Updating state triggers re-render
- State updates are asynchronous
Multiple State Variables
Declare multiple independent state variables:
function UserForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [age, setAge] = useState(0);
// Handle each independently
}
useEffect: Side Effects and Lifecycle
useEffect handles side effects—data fetching,
subscriptions, manual DOM updates:
import { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data));
}, [userId]); // Dependency array
return <div>{user?.name}</div>;
}
Dependency Arrays
The second argument controls when effects run:
useEffect(() => {
// Runs after every render
});
useEffect(() => {
// Runs once after initial render
}, []);
useEffect(() => {
// Runs when dependency changes
}, [dependency]);
Cleanup Functions
Return a function to clean up side effects:
useEffect(() => {
const timer = setInterval(() => {
console.log('tick');
}, 1000);
return () => clearInterval(timer); // Cleanup
}, []);
Common Mistakes
- Missing dependencies: Always include variables used inside effects
- Infinite loops: Updating state without proper dependencies
- Not cleaning up: Leaving subscriptions or timers running
// Infinite loop - BAD
useEffect(() => {
setCount(count + 1); // Updates every render
});
// Correct
useEffect(() => {
setCount(c => c + 1); // Runs once
}, []);
Mastering these two hooks provides the foundation for all other React hooks and modern component patterns.