# compose() de @wordpress/compose combine plusieurs HOC pour un même bloc

> Empiler withSelect, withDispatch et withInstanceId à la main produit vite un mur de parenthèses. La fonction compose() range cette pile proprement, dans l'ordre.

- Auteur : WordPress Développement
- Publié le : 2020-04-24
- Mis à jour le : 2020-04-24
- Catégorie : Blocs Gutenberg
- URL : https://www.wpmoderne.fr/blocs/compose-wordpress-compose-combiner-hoc-bloc/

## L’essentiel

- Empile plusieurs HOC sans imbrication visuelle
- Applique les fonctions de droite à gauche
- Reste compatible avec les hooks React sur le même composant

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()

> L'essentiel à retenir : Empile plusieurs HOC sans imbrication visuelle ; Applique les fonctions de droite à gauche ; Reste compatible avec les hooks React sur le même composant

`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 appeler `useState` ou `useEffect` en 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 `README` du 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.
