Combiner useEffect & Routing
Le vrai pouvoir vient de la combinaison de useEffect et du routing pour creer des applications multi-pages avec donnees dynamiques.
L'idee cle
Les dependances de useEffect peuvent venir de useParams() ou useSearchParams(). Quand l'URL change, React met a jour ces valeurs, ce qui re-declenche automatiquement vos effets.
const { userId } = useParams();
useEffect(() => {
// Ce code se re-execute automatiquement quand l'URL change !
fetch(`/api/users/${userId}`);
}, [userId]);
Pattern Principal : Fetch Base sur les Params d'URL
Le pattern le plus courant : recuperer des donnees differentes selon l'URL.
import { useParams } from 'react-router-dom';
import { useState, useEffect } from 'react';
function UserProfile() {
const { userId } = useParams();
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchUser() {
setLoading(true);
// Pour la clarte, error handling omis - voir section Data Fetching
const response = await fetch(
`https://jsonplaceholder.typicode.com/users/${userId}`
);
const data = await response.json();
setUser(data);
setLoading(false);
}
fetchUser();
}, [userId]); // Re-fetch quand userId change
if (loading) return <div>Chargement...</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
// Route
<Route path="/users/:userId" element={<UserProfile />} />
Timeline :
1. User navigue vers /users/1
→ useParams() retourne { userId: "1" }
→ useEffect se declenche
→ Fetch user 1
2. User navigue vers /users/2
→ useParams() retourne { userId: "2" }
→ userId a change → useEffect se re-declenche
→ Fetch user 2
Dependance critique
Toujours mettre les params d'URL dans les dependances de useEffect !
// ✅ Bon : re-fetch si userId change
useEffect(() => {
fetch(`/api/users/${userId}`);
}, [userId]);
// ❌ Mauvais : fetch une seule fois, ignore les changements d'URL
useEffect(() => {
fetch(`/api/users/${userId}`);
}, []);
Pourquoi faut-il mettre userId dans les dependances de useEffect quand on fetch des donnees basees sur l'URL ?
Pattern : Fetch avec Search Params
Les search params (?page=2&sort=name) peuvent aussi servir de dependances pour useEffect. Utile pour la pagination :
import { useSearchParams } from 'react-router-dom';
function PostList() {
const [searchParams, setSearchParams] = useSearchParams();
const [posts, setPosts] = useState([]);
const page = parseInt(searchParams.get('page') || '1', 10);
const limit = 10;
useEffect(() => {
async function fetchPosts() {
const start = (page - 1) * limit;
// Pour la clarte, error handling omis - voir section Data Fetching
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts?_start=${start}&_limit=${limit}`
);
const data = await response.json();
setPosts(data);
}
fetchPosts();
}, [page]); // Re-fetch quand la page change
return (
<div>
<h1>Posts - Page {page}</h1>
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
<div>
<button
onClick={() => page > 1 && setSearchParams({ page: page - 1 })}
disabled={page === 1}
>
Precedent
</button>
<span>Page {page}</span>
<button onClick={() => setSearchParams({ page: page + 1 })}>
Suivant
</button>
</div>
</div>
);
}
URLs :
/posts → Page 1
/posts?page=2 → Page 2
/posts?page=3 → Page 3
Exemple Complet : Annuaire Utilisateurs
Voici un exemple qui combine tout : routing, fetch avec useParams, et Promise.all pour la performance.
import { Routes, Route, Link, useParams } from 'react-router-dom';
import { useState, useEffect } from 'react';
// Page 1 : Liste des utilisateurs
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchUsers() {
// Pour la clarte, error handling omis - voir section Data Fetching
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await response.json();
setUsers(data);
setLoading(false);
}
fetchUsers();
}, []);
if (loading) return <div>Chargement...</div>;
return (
<div>
<h1>Utilisateurs</h1>
<ul>
{users.map(user => (
<li key={user.id}>
<Link to={`/users/${user.id}`}>
{user.name}
</Link>
</li>
))}
</ul>
</div>
);
}
// Page 2 : Profil utilisateur avec ses posts
function UserProfile() {
const { userId } = useParams();
const [user, setUser] = useState(null);
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchUserData() {
setLoading(true);
// Fetch en parallele avec Promise.all
const [userResponse, postsResponse] = await Promise.all([
fetch(`https://jsonplaceholder.typicode.com/users/${userId}`),
fetch(`https://jsonplaceholder.typicode.com/posts?userId=${userId}`)
]);
const userData = await userResponse.json();
const postsData = await postsResponse.json();
setUser(userData);
setPosts(postsData);
setLoading(false);
}
fetchUserData();
}, [userId]); // Re-fetch si on navigue vers un autre utilisateur
if (loading) return <div>Chargement...</div>;
return (
<div>
<Link to="/users">← Retour a la liste</Link>
<h1>{user.name}</h1>
<p>Email : {user.email}</p>
<h2>Articles de {user.name}</h2>
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
// App
function App() {
return (
<Routes>
<Route path="/users" element={<UserList />} />
<Route path="/users/:userId" element={<UserProfile />} />
</Routes>
);
}
Que se passe-t-il quand on navigue de /users/1 a /users/2 avec le meme composant UserProfile ?
Eviter les race conditions
Quand l'utilisateur change de page rapidement, les anciennes requetes peuvent arriver apres les nouvelles et causer des affichages incorrects. Utilisez le pattern AbortController vu dans la section Data Fetching pour annuler les requetes obsoletes dans le cleanup de useEffect.
Recapitulatif
Comprendre, pas memoriser
Ce qu'il faut retenir :
- Dependances depuis l'URL →
useParams()etuseSearchParams()fournissent des valeurs reactives pouruseEffect - Fetch + params →
useEffect([id])re-fetch automatiquement quand l'URL change - Pagination →
useSearchParams()+useEffect([page])pour naviguer entre les pages - Promise.all → lancer plusieurs fetch en parallele pour la performance
C'est en combinant useEffect et routing que vous creez des applications React completes !
Prochaine Etape
Vous maitrisez maintenant useEffect et le routing ! Passons a la pratique avec des exercices concrets pour consolider vos connaissances.