State and Hooks
Learn how to manage component state using React hooks like useState and useEffect
State and Hooks
State allows React components to change their output over time in response to user actions, network responses, and anything else.
What is State?
State is data that can change over time. When state changes, React re-renders the component to reflect the new state.
useState Hook
The useState hook lets you add state to function components:
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}useEffect Hook
The useEffect hook lets you perform side effects in function components:
import { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(seconds => seconds + 1);
}, 1000);
// Cleanup function
return () => clearInterval(interval);
}, []); // Empty dependency array means this effect runs once
return <div>Timer: {seconds} seconds</div>;
}Managing Complex State
For more complex state, you can use multiple useState calls or useReducer:
function UserProfile() {
const [user, setUser] = useState({
name: '',
email: '',
age: 0
});
const updateUser = (field, value) => {
setUser(prevUser => ({
...prevUser,
[field]: value
}));
};
return (
<form>
<input
type="text"
value={user.name}
onChange={(e) => updateUser('name', e.target.value)}
placeholder="Name"
/>
<input
type="email"
value={user.email}
onChange={(e) => updateUser('email', e.target.value)}
placeholder="Email"
/>
<input
type="number"
value={user.age}
onChange={(e) => updateUser('age', parseInt(e.target.value))}
placeholder="Age"
/>
</form>
);
}Effect Dependencies
The dependency array in useEffect determines when the effect runs:
// Runs on every render
useEffect(() => {
console.log('Runs on every render');
});
// Runs only once (on mount)
useEffect(() => {
console.log('Runs only once');
}, []);
// Runs when count changes
useEffect(() => {
console.log('Count changed:', count);
}, [count]);Common Patterns
Fetching Data
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/users')
.then(response => response.json())
.then(data => {
setUsers(data);
setLoading(false);
});
}, []);
if (loading) return <div>Loading...</div>;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}Rules of Hooks
- Only call hooks at the top level of your React function
- Only call hooks from React functions (components or custom hooks)
- Use the ESLint plugin for React hooks to catch violations
Exercise
Create a todo list component that allows users to add, remove, and toggle the completion status of todo items using useState.
Next up: We'll learn about handling events and forms in React!