Quatre. C’est le nombre de composants d’ordre supérieur qu’un bloc un peu ambitieux accumule facilement en 2020 : withSelect pour lire des données, withDispatch pour les modifier, withInstanceId pour générer un identifiant unique, et parfois un HOC maison pour gérer un état local partagé. Écrits à la main, ces quatre appels s’imbriquent les uns dans les autres et produisent un empilement de parenthèses fermantes difficile à relire.
La fonction compose(), fournie par le paquet @wordpress/compose, résout ce problème d’écriture sans rien changer au comportement : elle prend une liste de fonctions et retourne une fonction unique qui les applique successivement au composant de départ.
Le problème que compose() résout
Sans compose(), appliquer trois HOC à un composant Edit ressemble à ceci :
export default withInstanceId(
withDispatch( mapDispatchToProps )(
withSelect( mapSelectToProps )( Edit )
)
);
Chaque nouvelle couche ajoute un niveau d’imbrication et une parenthèse à retrouver en fin de ligne. Sur un bloc qui grossit avec le temps, ce style devient une source d’erreurs bêtes : une parenthèse oubliée, un HOC ajouté au mauvais niveau, un diff Git illisible.
La même chose avec compose()

compose() aplati cette pile en une liste lisible de haut en bas :
import { compose } from '@wordpress/compose';
import { withSelect, withDispatch } from '@wordpress/data';
import { withInstanceId } from '@wordpress/compose';
export default compose( [
withSelect( mapSelectToProps ),
withDispatch( mapDispatchToProps ),
withInstanceId,
] )( Edit );
Chaque ligne du tableau correspond à un HOC appliqué, dans le même ordre qu’on les lirait dans une phrase. Ajouter ou retirer un comportement revient à ajouter ou supprimer une ligne, sans toucher à la structure d’ensemble.
L’ordre d’application compte
Un point mérite une attention particulière : compose() applique les fonctions dans l’ordre du tableau, mais chaque HOC enveloppe le résultat du précédent. Concrètement, le premier élément du tableau est le plus proche du composant final rendu, et le dernier élément est le plus extérieur. Sur l’exemple ci-dessus, withInstanceId reçoit un composant déjà enrichi par withDispatch, lui-même appliqué sur un composant déjà enrichi par withSelect.
Cet ordre a des conséquences pratiques : si withDispatch a besoin d’une prop injectée par withSelect (par exemple un identifiant d’article récupéré via une sélection), withSelect doit impérativement apparaître avant dans le tableau.
Composer avec ses propres fonctions
Rien n’empêche d’ajouter un HOC maison à la liste, tant qu’il respecte la même signature : une fonction qui prend un composant et retourne un composant.
const withMonHistorique = ( Composant ) => ( props ) => {
// logique locale, indépendante du magasin de données
return <Composant { ...props } />;
};
export default compose( [
withSelect( mapSelectToProps ),
withMonHistorique,
] )( Edit );
Cette souplesse explique pourquoi compose() reste répandu même sur des blocs qui n’utilisent pas uniquement les HOC fournis par WordPress.
Cohabitation avec les hooks React
compose()ne remplace pas les hooks React (useSelect,useDispatch), il cohabite avec eux.- Un composant enveloppé par
compose()peut très bien appeleruseStateouuseEffecten interne. - Migrer un bloc existant se fait généralement HOC par HOC, pas d’un seul coup sur tout le fichier.
compose()vient à l’origine de la bibliothèque Redux et son fonctionnement (composition de fonctions de droite à gauche, au sens mathématique) est identique.
Ce qu’il faut retenir avant de choisir
Sur un bloc neuf en 2020, la question se pose légitimement : partir directement sur les hooks React, plus récents, ou continuer avec compose() et les HOC historiques ? La réponse dépend surtout de l’existant : sur un projet qui compte déjà plusieurs blocs écrits avec des HOC, garder la même convention facilite la maintenance. Sur un bloc entièrement neuf, les hooks réduisent le nombre de couches à lire.
Sur nos projets qui mélangent les deux générations de blocs, on documente systématiquement dans le fichier
READMEdu bloc quelle convention a été choisie, pour éviter qu’un nouveau développeur ne mélange les deux styles dans le même composant.
En résumé
compose() ne change rien au comportement d’un bloc, seulement sa lisibilité. Sur un bloc qui empile trois ou quatre comportements distincts, la différence entre un mur de parenthèses et une liste ordonnée se ressent dès la première relecture par un collègue. Le paquet @wordpress/compose reste au cœur de l’éditeur de blocs, hooks ou pas.