Les différents modèles de récupération de données dans React
Court résumé de quelques possibilités
Note: Cet article se concentre sur les modèles de récupération de données dans les composants React, aussi bien côté client que côté serveur.
Il est important de préciser que cet article n'aborde pas les différentes méthodes de récupération des données (comme fetch
ou des bibliothèques comme Axios), mais plutôt les schémas d'organisation pour structurer cette récupération dans les composants React. Il ne s'agit pas d'une liste exhaustive, mais d'une présentation des modèles courants rencontrés lors du développement d'applications React.
1. Récupération de données séquentielle
La récupération de données séquentielle (aussi appelée requêtes en cascade) est l'un des modèles les plus courants. Ici, chaque étape dépend des données obtenues lors de la précédente. Il faut distinguer deux cas :
Accidentelle : lorsque les requêtes s'enchaînent sans que ce soit intentionnel.
Intentionnelle : lorsque les requêtes doivent absolument suivre un ordre logique.
Exemple (accidentel) :
Un composant parent récupère un article et un composant enfant récupère les commentaires associés :
const Post = async ({ postId }: { postId: string }) => {
const post = await getPost(postId);
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
<Comments postId={post.id} />
</div>
);
};
const Comments = async ({ postId }: { postId: string }) => {
const comments = await getComments(postId);
return (
<ul>
{comments.map((comment) => (
<li key={comment.id}>{comment.content}</li>
))}
</ul>
);
};
Dans cet exemple, la récupération des commentaires dépend de celle de l'article. Cependant, si vous utilisez une bibliothèque comme React Query pour le côté client, vous devrez gérer explicitement les états de chargement, erreur et succès :
const Post = ({ postId }: { postId: string }) => {
const { data: post, isLoading } = usePost(postId);
if (isLoading) return <p>Chargement...</p>;
if (!post) return <p>Article introuvable.</p>;
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
<Comments postId={post.id} />
</div>
);
};
Cas intentionnel :
Dans des applications complexes, vous pouvez avoir besoin de récupérer les données séquentiellement pour respecter une logique métier. Dans ce cas, il peut être judicieux de regrouper les requêtes côté API (par exemple, avec un join SQL ou en utilisant GraphQL).
2. Récupération de données en parallèle
Lorsque les données à récupérer sont indépendantes les unes des autres, vous pouvez opter pour une récupération en parallèle afin d'améliorer les performances. Cela implique de déplacer la logique de récupération à un niveau supérieur.
Exemple :
const Post = async ({ postId }: { postId: string }) => {
const postPromise = getPost(postId);
const commentsPromise = getComments(postId);
const [post, comments] = await Promise.all([postPromise, commentsPromise]);
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
<Comments comments={comments} />
</div>
);
};
const Comments = ({ comments }: { comments: Comment[] }) => (
<ul>
{comments.map((comment) => (
<li key={comment.id}>{comment.content}</li>
))}
</ul>
);
Avec l'API Promise, les deux requêtes sont effectuées en parallèle, réduisant ainsi le temps total de récupération. Ce modèle est particulièrement utile lorsque les données n'ont pas de dépendance entre elles.
3. Pré-chargement des données
Pour améliorer la perception des performances, vous pouvez pré-charger les données susceptibles d’être utilisées prochainement. Cela permet de rendre l'application plus fluide.
Exemple avec Next.js :
Le composant Link
permet de précharger les données de la page suivante :
<Link href="/posts/1" prefetch>
<a>Article 1</a>
</Link>
Dès que le lien entre dans le champ de vision de l'utilisateur, les données sont préchargées. Ce principe peut également être appliqué à d'autres bibliothèques (comme React Query), où la récupération doit être déclenchée manuellement.
4. Utilisation de données initiales
Dans le contexte des composants côté serveur et client dans React, vous pouvez charger les données sur le serveur pour les fournir comme état initial à un composant client. Cela évite un affichage initial vide côté client.
Exemple :
Composant côté serveur :
const Comments = async ({ postId, page }: { postId: string; page: number }) => {
const comments = await getComments(postId, page);
return <CommentList initialComments={comments} />;
};
Composant côté client :
const CommentList = ({ initialComments }: { initialComments: Comment[] }) => {
const [comments, setComments] = useState(initialComments);
return (
<ul>
{comments.map((comment) => (
<li key={comment.id}>{comment.content}</li>
))}
</ul>
);
};
Ce modèle permet d'éviter un état de chargement initial sur le client, offrant une expérience utilisateur plus fluide.
Conclusion
Il existe de nombreux modèles pour structurer la récupération de données dans une application React. L'essentiel est de comprendre les compromis de chaque modèle (performance, complexité, expérience utilisateur) et de choisir celui qui convient le mieux à votre cas d'utilisation.
Guillaume Duhan