Logo Zéphyrnet

La puissance de la composition des composants dans React

Date :

L'un des problèmes les plus difficiles dans la création d'une application Web complexe est la façon dont nous structurons notre code. Depuis l'aube de React, le principal moyen d'encapsuler la logique et la fonctionnalité est devenu le modèle de composants. Plus récemment, cette idée s'est même propagée à d'autres frameworks et bibliothèques.

Avant d'en arriver à React, voici un extrait de code, j'aimerais savoir ce que vous pensez être intéressant à ce sujet :

<select options={[ { value: 'value1' label: 'label1' }, { value: 'value2' label: 'label2' }, { value: 'value3' label: 'label3' }]
} />

Aïe ! Heureusement, c'est juste inventé, et en réalité, nous pouvons réellement utiliser le select élément comme celui-ci :

<select> <option value="value1">label1</option> <option value="value2">label2</option> <option value="value3">label3</option>
</select>

Il s'agit en fait d'un exemple très courant de composition, et c'est une excellente API simple. Considérons maintenant la façon dont nous construisons des composants dans React. Prenons l'exemple d'un composant Alert qui doit prendre en charge quelques variantes.

<Alert header="Success alert" variant="success" icon="success" description="This is a success alert message"
/> <Alert header="Info alert" variant="info" icon="info" description="This is an info alert message"
/> <Alert header="Error alert" variant="error" icon="error" description="This is an error alert message"
/>

Que diriez-vous si nous voulons que l'icône s'affiche sur le côté opposé ? Nous rajouterions un iconPosition accessoire je suppose 🤔

<Alert header="Error alert" variant="error" icon="error" description="This is an error alert message" iconPosition="left"
/>

Si vous avez déjà créé du code qui a été utilisé à plusieurs endroits auparavant, vous connaissez probablement cette histoire :

  1. Vous construisez un morceau de code réutilisable (fonction, composant React ou hook React, etc.) et le partagez (avec des collègues ou publiez-le en tant qu'OSS).
  2. Quelqu'un vous approche avec un nouveau cas d'utilisation que votre code ne prend pas tout à fait en charge, mais pourrait le faire avec un petit ajustement.
  3. Vous ajoutez un argument/prop/option à votre code réutilisable et à la logique associée pour que ce cas d'utilisation soit pris en charge.
  4. Répétez les étapes 2 et 3 plusieurs fois (ou plusieurs fois 😬).
  5. Le code réutilisable est désormais un cauchemar à utiliser et à entretenir 😭

(les étapes ci-dessus proviennent de L'article de Kent Dodd)

Il semble que nous nous retrouverions rapidement avec un composant très compliqué, avec des dizaines d'accessoires et de nombreuses utilisations à prendre en compte. Il existe une autre approche, cependant, et c'est la composition des composants.

Qu'est-ce que la composition des composants ?

En termes simples, cela signifie simplement composer des composants ensemble pour former d'autres composants. Concrètement, cela se fait principalement en utilisant le children soutenir. Je pense que c'est une fonctionnalité de React qui est sous-utilisée, bien qu'elle nous permette de créer des composants flexibles et agréables à utiliser.

Voyons comment le Alert le composant ressemblerait si nous utilisions la composition :

<Alert status="error"> <Icon /> <Alert.Title>Your browser is outdated!</Alert.Title> <Alert.Description>Your Volunteer Hub experience may be degraded.</Alert.Description>
</Alert>

Cela ouvre beaucoup plus d'options. Nous pouvons facilement étendre ou remplacer les fonctionnalités sans modifier la logique des composants. Nous avons plus de contrôle 🤓

export const Alert = ({ status, children }) => { return ( <div className={status}> {children} </div> )
} Alert.Title = function AlertTitle({ children }) { return ( <span className="alert-title">{children}</span> )
} Alert.Description = function AlertDescription({ children }) { return ( <span className="alert-description">{children}</span> )
}

Inversion de contrôle

L'inversion de contrôle (IoC) est un modèle de conception qui signifie simplement (dans le contexte des composants) déplacer une partie du contrôle du composant lui-même vers l'endroit où il est utilisé.

Prenons un autre exemple de Menu composant. Une façon courante de le construire ressemble à ceci:

<Menu button={<button>Menu</button>} items={[ {contents: 'Download', onSelect: () => console.log('Download')}, {contents: 'Create a Copy', onSelect: () => console.log('Create a Copy')}, {contents: 'Delete', onSelect: () => console.log('Delete')}, ]}
/>

Que se passe-t-il si nous voulons ajouter un séparateur entre certains éléments du menu afin qu'ils soient regroupés ? Peut-être pouvons-nous le faire via une propriété supplémentaire sur un objet d'élément, mais cela introduit encore plus de complexité.

Lors de la création d'un nouveau composant, cela vaut la peine de passer un peu de temps à décider comment nous voulons qu'il soit utilisé afin de produire une belle API pour les autres (ou nous-mêmes futurs) qui utiliseront ce composant à l'avenir. Dans ce cas, et si nous donnions une partie de la responsabilité du rendu à l'utilisateur de notre composant ?

<Menu> <Menu.Button>Menu</Menu.Button> <Menu.List> <Menu.Item onSelect={() => console.log('Download')}>Download</Menu.Item> <Menu.Item onSelect={() => console.log('Copy')}>Create a Copy</Menu.Item> <Divider /> <Menu.Item onSelect={() => console.log('Delete')}>Delete</Menu.Item> </Menu.List>
</Menu>

Celui-ci serait un peu plus complexe à construire qu'un composant Alert, mais le résultat final est très flexible et en vaut la peine.

Comment puis-je y parvenir?

Lorsqu'il s'agit de construire des composants composés un peu plus complexes, comme l'exemple de menu ou peut-être un composant accordéon, onglets ou modal, nous aurons besoin d'un peu plus que de simplement passer children et appliquer un peu de style. Nous pourrions avoir besoin d'un état partagé ou d'un ensemble de fonctions auxquelles les sous-composants ont accès. Voici quelques modèles dont vous pourriez avoir besoin :

  • Utilisation de l'API de contexte dans l'élément parent pour stocker l'état partagé
  • Utilisation de l'API enfants de niveau supérieur (comme Children.mapou Children.forEach)

Où dois-je aller?

Cet article était uniquement destiné à vous donner un avant-goût de ce que la composition des composants peut réaliser. Je n'ai pas donné beaucoup de détails sur la façon d'y parvenir, car il existe en fait de nombreuses excellentes ressources qui expliquent très bien comment y parvenir. Voilà quelque:

spot_img

Dernières informations

spot_img

Discutez avec nous

Salut! Comment puis-je t'aider?