Chargez des données distantes avec fetch dans un effet, en modélisant proprement les états de chargement et d'erreur.
Ouvrir cette leçon dans KodokonUne requête réseau met du temps et peut échouer : votre interface doit refléter ces réalités. La convention professionnelle consiste à suivre trois états distincts : les données reçues, un booléen de chargement et une éventuelle erreur. La requête part dans un useEffect, car contacter un serveur est un effet de bord.
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch("https://api.example.com/users")
.then((res) => {
if (!res.ok) throw new Error("HTTP " + res.status);
return res.json();
})
.then((data) => setUsers(data))
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
}, []);Au rendu, traitez les cas dans l'ordre : d'abord le chargement, puis l'erreur, enfin les données. Ces retours anticipés gardent le code lisible et garantissent que l'utilisateur voit toujours quelque chose de cohérent : un indicateur d'attente, un message d'échec ou la liste attendue.
if (loading) return <p>Chargement…</p>;
if (error) return <p>Erreur : {error}</p>;
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);Dernier piège : si une dépendance change (un userId par exemple), une nouvelle requête part alors que l'ancienne est peut-être encore en vol. Si l'ancienne répond en dernier, elle écraserait les données fraîches. La parade classique : un drapeau ignore remis à true par la fonction de nettoyage, pour jeter les réponses obsolètes.
useEffect(() => {
let ignore = false;
setLoading(true);
fetch("/api/users/" + userId)
.then((res) => res.json())
.then((data) => {
if (!ignore) setUser(data);
})
.finally(() => {
if (!ignore) setLoading(false);
});
return () => {
ignore = true;
};
}, [userId]);catch ne se déclenche pas. Pourquoi ?ignore remis à true dans le nettoyage de l'effet ?