La solution pour organiser vos composants, c’est le pattern Presentational/Container. On a vu dans le précédent article comment penser un bon composant un contexte clair et une responsabilité unique. On s’attaque maintenant à comment les organiser correctement ensemble.
Ce pattern est simple mais très efficace. Il n’existe pas de définition parfaitement consensuelle, mais voici celle que je trouve la plus pertinente :
Presentational Components: des composants qui se soucient uniquement de la façon dont une donnée spécifique est affichée à l’utilisateur.
Container Components: des composants qui se soucient principalement de quelles données sont affichées par quel composant à l’utilisateur.
Pour des raisons de simplicité, nous utiliserons les termes « smart » et « dumb » dans la suite de l’article.
Ce pattern propose de séparer la logique de la vue. Autrement dit, de distinguer les composants utilisés pour afficher des données à l’utilisateur de ceux chargés d’appeler ou de transformer ces données.
Les presentational : revisiter l’atomic design
L’atomic design est une méthodologie de création d’interfaces web proposée par Brad Frost en 2015. Elle repose sur la distinction de cinq niveaux de conception. Le principe est clair : les atomes se combinent pour former des molécules, qui elles-mêmes composent des organismes, puis des templates, et enfin des pages.
Dans notre cas, nous ne conserverons que les niveaux atomique et moléculaire. Les autres sont rarement utiles : les templates et les pages ne sont souvent que des assemblages spécifiques, difficiles à réutiliser. Les frontières deviennent floues à mesure qu’on monte dans la hiérarchie.
Nos composants dumb se répartissent donc en deux catégories.
Un composant atomique tolère une certaine généricité : lire un terme comme « item » dans ce contexte n’a rien de choquant. Ce sont les briques réutilisables, sans logique métier : les boutons, les champs de saisie, les icônes… bref, les éléments du design system. Leur rôle est limité à l’affichage et à la gestion des interactions simples.
Les composants moléculaires , eux, représentent un contexte plus concret. Ils rassemblent plusieurs composants atomiques et un tout petit peu de logique pour répondre à un besoin précis dans une situation donnée. Un article-card en est un bon exemple.
Faire cette distinction dès le départ permet de gagner énormément de temps. On identifie immédiatement les composants réutilisables à l’échelle du projet et ceux qui appartiennent à un contexte spécifique, ce qui aide à préserver à la fois le contexte et la responsabilité de chaque composant.
Les containers : utiliser les pages
Viennent ensuite les composants responsables de la logique et de la cohérence des données. Ce rôle est confié aux pages. Une page est donc responsable de récupérer, transformer et distribuer les données aux composants enfants qui s’occupent de la présentation. Elle gère à la fois la logique et le layout.
Certains préfèrent déléguer la gestion du layout à d’autres structures et conserver dans la page uniquement la logique. C’est possible, mais cette approche tend à complexifier inutilement le code. En pratique, il est souvent plus simple et plus lisible de regrouper ces deux aspects dans un seul composant page.
Concrètement, tous les appels HTTP et les interactions avec le store se font au niveau de la page. Celle-ci transforme ensuite les données et les passe à ses enfants dans le format exact qu’ils attendent. Cette structure rend quasi inévitable la mise en place d’un flux de données unidirectionnel. On peut suivre la donnée depuis le back-end jusqu’à la vue de manière prévisible et simple : les données entrent dans l’application, sont transformées en amont, puis distribuées par morceaux dans les composants purement visuels.
L’objectif n’est pas de promouvoir le props drilling excessif ou la remontée d’événements dans tous les sens, mais simplement de limiter les effets de bord. En cascade, la lecture du code reste claire et les mutations d’état imprévues sont contenues, ce qui réduit les risques de désynchronisation entre composants et conserve une architecture lisible et stable dans le temps.
Mention honorable : One-way Data Flow
Cette organisation n’est pas arbitraire : elle découle d’un principe plus fondamental, le flux de données unidirectionnel. Les données entrent par le haut, au niveau de la page, et descendent vers les composants enfants. Jamais l’inverse. Un composant dumb reçoit des données, les affiche et remonte des événements mais il ne va jamais chercher lui-même ce qu’il doit afficher.
Ce flux prévisible est ce qui rend le projet maintenable sur la durée. Quand un bug apparaît, vous savez exactement où regarder : si l’affichage est faux, le problème est dans le composant dumb. Si la donnée est fausse, le problème est dans la page. Le débogage devient mécanique plutôt qu’instinctif.
Quelques conseils
Avant de conclure, quelques points à garder en tête sur l’utilisation de ce pattern :
- Il n’y a aucun problème à imbriquer un composant smart dans un autre smart.
- Ce n’est pas absolu : un composant dumb peut parfois appeler une API, notamment s’il gère une configuration qui lui est propre.
- Certains frameworks et librairies de state management : Vue.js avec Pinia, par exemple rendent ce pattern largement superflu.
- Évitez de trop driller vos props à travers plusieurs niveaux de composants.
Une bonne architecture, c’est la base de la scalabilité et de la maintenabilité d’un projet c’est d’autant plus vrai pour les applications qui vivent plusieurs années et où les développeurs se succèdent. Ce pattern ne révolutionne pas votre code du jour au lendemain. Mais dans six mois, quand un nouveau développeur ouvre le projet pour la première fois, il saura exactement où chercher la logique et où chercher l’interface. C’est tout l’intérêt.
Pour finir cette série, un dernier article la semaine prochaine autour de l’histoire de ce pattern parce que comprendre d’où viennent les idées change la façon dont on les utilise.



Top comments (0)