Comment utiliser des composants d’ordre supérieur pour réutiliser la logique dans React –
Les composants d’ordre supérieur (HOC) sont une sorte de composant React qui vous aide à réutiliser la logique dans votre application. La terminologie peut sembler complexe, mais les HOC sont faciles à maîtriser et peuvent simplifier la maintenance de votre base de code.
Un composant d’ordre supérieur enveloppe toujours les composants enfants avec des fonctionnalités supplémentaires. Un HOC est défini comme une fonction qui accepte un composant comme paramètre. Il renvoie ensuite un Nouveau composant, qui rendra généralement le composant d’entrée enveloppé d’accessoires supplémentaires.
Sommaire
Un exemple simple
La meilleure façon d’apprécier quand les HOC ont un sens est de les voir en action. Considérons un système de paiement simple où l’état du panier de l’utilisateur est stocké de manière centralisée dans l’application. Nos exemples montrent Redux comme magasin d’état, mais ceci à des fins d’illustration uniquement.
Supposons que cet objet représente l’état de notre application:
{ checkout: { items: [ { label: "Product 1", price: 150.00, quantity: 2 }, { label: "Product 2", price: 75.00, quantity: 1 } ] } }
Nous avons un tableau simple qui représente les articles dans le panier de l’utilisateur. Nos composants de paiement vont dériver des valeurs supplémentaires de cet état, telles que la valeur totale de la commande et les taxes à appliquer.
Notre système de paiement devra probablement afficher la valeur totale dans plusieurs composants indépendants. Il peut y avoir un widget de barre latérale affichant le panier, un écran de révision après le paiement et un calculateur de frais d’expédition. Un système naïf qui transmettrait simplement les articles de caisse comme accessoires risquerait de faire double emploi avec la logique – chaque composant devrait calculer la valeur totale de la commande pour lui-même.
Présentation du HOC
Voyons comment un HOC peut vous aider:
import React from "react"; import {connect} from "react-redux"; const withCheckout = ComponentToWrap => { const ComponentWithCheckout = class extends React.Component { render() { return ( <ComponentToWrap checkoutItems={this.props.checkout.items} checkoutTotal={this.total} {...this.props} /> ); } get total() { const prices = this.props.checkout.items.map(i => (i.quantity * i.price)); return prices.reduce((a, b) => (a + b), 0); } } return connect(({checkout}) => ({checkout}))(ComponentWithCheckout); } export default withCheckout;
Le fichier exporte une seule fonction, withCheckout
, qui prend un composant React comme seul paramètre (ComponentToWrap
). Dans la fonction, nous créons une nouvelle classe anonyme qui est elle-même un composant React.
Ce nouveau composant render
crée une instance de la ComponentToWrap
nous sommes passés à la fonction. Nous avons maintenant la possibilité de définir les accessoires de l’instance. Nous transmettons le tableau des articles de caisse comme checkoutItems
et rendre la valeur totale pré-calculée disponible comme checkoutTotal
.
Tous les accessoires transmis au HOC sont transmis au composant interne, garantissant qu’il reçoit toutes les données dont il a besoin. La fonction renvoie la classe anonyme nouvellement créée qui est prête à être rendue dans toute votre application.
Nous utilisons le connect
méthode de react-redux
alors le checkout
prop au sein du HOC reçoit la valeur du checkout
clé dans l’état de notre boutique Redux. Il s’agit d’un détail d’implémentation – votre HOC peut conserver son propre état ou contacter un autre service de votre application.
Utilisation du HOC
Il est maintenant temps d’utiliser notre HOC.
import React from "react"; import withCheckout from "./withCheckout.js"; class CheckoutReviewScreen extends React.Component { render() { return ( <h1>Checkout</h1> <h2>{this.props.checkoutTotal}</h2> ); } } export default withCheckout(CheckoutReviewScreen);
Nous assumons notre withCheckout
HOC est enregistré dans withCheckout.js
dans le même répertoire que notre nouveau composant d’écran d’examen de la caisse. En enveloppant le composant avec notre withCheckout
HOC, nous pouvons accéder et afficher la valeur totale de la commande. Nous n’avons pas besoin de le calculer nous-mêmes ni de le stocker dans l’état de l’application. Si nous avons toujours voulu mettre à jour la façon dont le total est calculé (par exemple pour ajouter des frais de traitement fixes), nous n’avons besoin de faire le changement qu’à un seul endroit – au sein de notre HOC.
Vous pouvez maintenant rendre <CheckoutReviewScreen />
n’importe où dans votre application. Notre exemple encapsulé n’a pas besoin de recevoir d’accessoires car il tire ses données de notre magasin Redux. Parce qu’il est enveloppé de withCheckout
, lui-même enveloppé de Redux connect
, l’écran de révision reçoit automatiquement un checkoutTotal
prop qui additionne les prix de tous les articles dans l’état de l’application.
Il convient maintenant de mentionner comment nous avons nommé notre HOC: withCheckout
. Par convention, les noms HOC ont normalement un with
préfixe car ils ajoutent quelque chose aux composants qu’ils enveloppent. Dans notre cas, le HOC fournit un accès pratique à notre panier de paiement que nous aurions autrement besoin de mettre en œuvre dans chaque composant.
Avantages des HOC
L’utilisation d’un HOC vous permet d’abstraire les comportements courants des composants, minimisant la duplication de code et augmentant la maintenabilité. Les HOC permettent une forme d’injection de dépendances. Ils vous aident à simplifier vos composants en permettant de transmettre davantage du monde extérieur.
Les HOC sont courants dans l’écosystème React. En fait, nous en avons vu un dans cet article – connect()
, partie de react-redux
, qui abonne vos composants aux changements d’état de Redux.
Les HOC sont populaires car ils fournissent une méthode de réutilisation du code qui ne rompt pas l’auto-confinement des composants. Le modèle utilise la composabilité de React pour vous permettre d’attacher des fonctionnalités supplémentaires sans risque d’effets secondaires.
Vous pouvez transmettre n’importe quel composant de votre application à withCheckout
sans rien casser – le HOC attache juste quelques accessoires supplémentaires. C’est pourquoi il est si important que vos HOC avancent tout les accessoires qu’ils reçoivent ({...this.props}
dans notre exemple). Ils ne doivent rien faire qui puisse interférer avec le fonctionnement normal du composant enveloppé.
Vous aurez peut-être l’impression que vos composants dépendent désormais de votre HOC. Ce n’est pas le cas. Vous pouvez exporter une deuxième version de votre composant qui n’est pas encapsulée, ce qui donne aux consommateurs le choix qu’ils utilisent.
Votre composant insiste en fait uniquement pour recevoir certains accessoires – checkoutTotal
dans notre cas. Cela peut être fourni par le HOC ou en passant une valeur partout où le composant est rendu. Notre HOC simplifie le développement mais n’a pas fondamentalement changé la nature de nos composants rendus.