Fermer

juin 8, 2020

Des composants d'ordre supérieur réagissent


À propos de l'auteur

Shedrack Akintayo est un ingénieur logiciel de Lagos, au Nigéria, qui aime le développement communautaire, l'open source et la création de contenu et de technologies pour les prochains…
En savoir plus sur
Shedrack

Dans ce didacticiel, nous allons découvrir les composants d'ordre supérieur, la syntaxe des composants d'ordre supérieur, ainsi que les cas d'utilisation de ces composants. Dans le processus, nous allons construire un composant d'ordre supérieur à partir d'un composant React existant. À la fin de ce didacticiel, vous comprendrez les principes de base des composants d'ordre supérieur et comment les construire.

Les composants d'ordre supérieur (HOC) dans React ont été inspirés par les fonctions d'ordre supérieur dans JavaScript. Un HOC est une technique avancée de réutilisation de la logique dans les composants React. C'est un modèle créé à partir de la nature compositionnelle de React.

Les HOC incorporent fondamentalement le principe de programmation de ne pas se répéter (DRY), que vous avez probablement rencontré à un moment donné de votre carrière de développeur de logiciels. . C'est l'un des principes les plus connus du développement logiciel, et l'observer est très important lors de la construction d'une application ou de l'écriture de code en général.

Dans ce didacticiel, nous allons apprendre ce qu'est un HOC, sa structure de base, une certaine utilisation et enfin un exemple.

Remarque: Les connaissances de base de React et de JavaScript vous seront utiles au fur et à mesure de ce didacticiel.

Meilleures pratiques avec React

React est un fantastique JavaScript bibliothèque pour la création d'interfaces utilisateur riches. Il fournit une excellente abstraction de composants pour organiser vos interfaces en un code qui fonctionne bien, et il y a à peu près tout ce que vous pouvez utiliser. Lire plus d'articles sur React →

Fonctions d'ordre supérieur en JavaScript

Avant de passer aux HOC dans React, discutons brièvement des fonctions d'ordre supérieur en JavaScript. Les comprendre est essentiel pour comprendre notre sujet de discussion.

Les fonctions d'ordre supérieur en JavaScript prennent certaines fonctions comme arguments et renvoient une autre fonction. Ils nous permettent d'abstraire plus de actions pas seulement des valeurs, ils se présentent sous plusieurs formes, et ils nous aident à écrire moins de code lors de l'utilisation de fonctions et même de tableaux.

La partie la plus intéressante de l'utilisation de plus haut -les fonctions d'ordre sont la composition. Nous pouvons écrire de petites fonctions qui gèrent un morceau de logique. Ensuite, nous pouvons composer des fonctions complexes en utilisant les différentes petites fonctions que nous avons créées. Cela réduit les bogues dans notre base de code et rend notre code beaucoup plus facile à lire et à comprendre.

JavaScript a déjà certaines de ces fonctions intégrées. Voici quelques exemples de fonctions d'ordre supérieur:

  • .forEach () [19659017] Ceci itère sur chaque élément d'un tableau avec le même code, mais ne modifie ni ne mute le tableau, et il renvoie undefined.
  • .map ()
    Cette méthode transforme un tableau en appliquant une fonction à tous de ses éléments, puis construction d'un nouveau tableau à partir des valeurs renvoyées.
  • .reduce ()
    Cette méthode exécute une fonction fournie pour chaque valeur du tableau (de gauche à droite).
  • .filter (
    Ceci vérifie chaque élément d'un tableau pour voir s'il répond à certains critères spécifiés dans la méthode de filtre puis il renvoie un nouveau tableau avec les éléments qui correspondent aux critères.

De nombreuses fonctions d'ordre supérieur sont intégrées à JavaScript, et vous pouvez créer votre propre o personnalisé

Un exemple de fonction d'ordre supérieur personnalisée

Supposons que l'on nous demande d'écrire une fonction qui formate les entiers en devises, y compris une certaine personnalisation de la spécification du symbole monétaire et l'ajout d'un séparateur décimal pour le montant en devise. Nous pouvons écrire une autre fonction supérieure qui prend le symbole monétaire et également le séparateur décimal. Cette même fonction formaterait alors la valeur qui lui est transmise avec le symbole monétaire et les opérateurs décimaux. Nous nommerions notre fonction d'ordre supérieur formatCurrency .

 const formatCurrency = function (
    symbole de la monnaie,
    séparateur décimal  ) {
    fonction de retour (valeur) {
        const wholePart = Math.trunc (valeur / 100);
        let fractionalPart = valeur% 100;
        if (fractionalPart 

formatCurrency renvoie une fonction avec un symbole monétaire fixe et un séparateur décimal.

Nous transmettons ensuite une valeur au formateur et formater cette valeur avec la fonction en extrayant toute sa partie et la partie fractionnaire. La valeur renvoyée de cette fonction est construite par un modèle littéral, concaténant le symbole monétaire, la partie entière, le séparateur décimal et la partie fractionnaire.

Utilisons cette fonction d'ordre supérieur en lui affectant une valeur et en voyant le résultat.

> getLabel = formatCurrency ('$', '.');
 
> getLabel (1999)
"19,99 $" // valeur formatée
 
> getLabel (2499)
"24,99 $" // valeur formatée

Vous avez peut-être remarqué que nous avons créé une variable nommée getLabel puis affecté notre formatCurrency fonction d'ordre supérieur, puis passé les formateurs de devises à la fonction, qui est la devise symbole et un séparateur décimal. Pour utiliser la fonction, nous appelons getLabel qui est maintenant une fonction, et nous transmettons la valeur qui doit être formatée. C'est tout! Nous avons créé un ordre supérieur personnalisé de notre choix.

Qu'est-ce qu'un composant d'ordre supérieur?

Un composant d'ordre supérieur (HOC) est un élément avancé pour la réutilisation de la logique dans les composants React. Les composants prennent un ou plusieurs composants comme arguments et renvoient un nouveau composant mis à niveau. Cela semble familier, non? Elles sont similaires aux fonctions d'ordre supérieur, qui prennent certaines fonctions en argument et produisent une nouvelle fonction.

Les HOC sont couramment utilisés pour concevoir des composants avec un certain comportement partagé d'une manière qui les rend connectés différemment de l'état à l'état normal.

Faits sur les HOC

  1. Nous ne modifions ni ne modifions les composants. Nous en créons de nouveaux.
  2. Un HOC est utilisé pour composer des composants pour la réutilisation de code.
  3. Un HOC est une fonction pure. Il n'a aucun effet secondaire, renvoyant uniquement un nouveau composant.

Voici quelques exemples de HOC réels que vous pourriez avoir rencontrés:

react-redux connect (mapStateToProps, mapDispatchToProps) (UserPage) [19659043] react-router withRouter (UserPage)
material-ui withStyles (styles) (UserPage)

Structure d'un composant d'ordre supérieur

Un HOC est structuré comme une fonction d'ordre supérieur :

  • C'est un composant.
  • Il prend un autre composant comme argument.
  • Ensuite, il renvoie un nouveau composant.
  • Le composant qu'il renvoie peut restituer le composant d'origine qui lui a été transmis. [19659024] L'extrait ci-dessous montre comment un HOC est structuré dans React:
    
    importer React à partir de 'react';
    // Prendre un composant comme argument WrappedComponent
    const upperOrderComponent = (WrappedComponent) => {
    // Et retourne un autre composant
      classe HOC étend React.Component {
        render () {
          retour ;
        }
      }
      retourner HOC;
    };
    

    Nous pouvons voir que upperOrderComponent prend un composant ( WrappedComponent ) et renvoie un autre composant à l'intérieur de celui-ci. Avec cette technique, chaque fois que nous devons réutiliser la logique d'un composant particulier pour quelque chose, nous pouvons créer un HOC à partir de ce composant et l'utiliser où nous le voulons.

    Cas d'utilisation

    D'après mon expérience en tant qu'ingénieur front-end qui écrit React depuis un certain temps maintenant, voici quelques cas d'utilisation des HOC.

    Afficher un chargeur pendant qu'un composant attend des données

    La plupart du temps, lors de la construction d'une application Web, nous aurait besoin d'utiliser un chargeur d'une sorte qui est affiché pendant qu'un composant attend que les données soient transmises à ses accessoires. Nous pourrions facilement utiliser une solution intégrée pour rendre le chargeur, ce qui fonctionnerait, mais ce ne serait pas la solution la plus élégante. Mieux serait d'écrire un HOC commun qui puisse suivre ces accessoires; et même si ces accessoires n'ont pas été injectés ou sont dans un état vide, il peut afficher un état de chargement.

    Pour expliquer cela correctement, construisons une liste de catégories d'API publiques à l'aide de son API ouverte. Nous avons tendance à gérer le chargement de liste, afin que nos clients ne paniquent pas lorsque l'API dont nous obtenons les données met tant de temps à répondre.

    Générons une application React:

     npx create-react-app repos -liste
    

    Un composant de liste de base peut s'écrire comme suit:

     // List.js
    importer React à partir de 'react';
    const List = (accessoires) => {
      const {repos} = accessoires;
      if (! repos) return null;
      si (! repos.length) retourne 

    Pas de repos, désolé

    ; revenir (
      {repos.map ((repo) => { return
    • {repo.full_name}
    • ; })}
    ); }; exporter la liste par défaut;

    Le code ci-dessus est un composant de liste. Décomposons le code en petits morceaux afin de comprendre ce qui se passe.

     const List = (props) => {};
    

    Ci-dessus, nous initialisons notre composant fonctionnel, nommé List et lui passons des accessoires.

     const {repos} = props;
    

    Ensuite, nous créons une constante, nommée repos et la transmettons à nos accessoires de composant, afin qu'elle puisse être utilisée pour modifier notre composant.

     if (! Repos) renvoie null;
    si (! repos.length) retourne 

    Pas de repos, désolé

    ;

    Ci-dessus, nous disons essentiellement que, si une fois l'extraction terminée et que l'accessoire repos est toujours vide, il devrait retourner null . Nous effectuons également un rendu conditionnel ici: si la longueur de l'accessoire repos est toujours vide, alors il devrait afficher "No repos, sorry" dans notre navigateur.

     return (
        
      {repos.map ((repo) => { return
    • {repo.full_name}
    • ; })}
    );

    Ici, nous mappons essentiellement le tableau repos et renvoyons une liste de dépôts selon leurs noms complets, avec une clé unique pour chaque entrée.

    Maintenant, écrivons un HOC qui gère chargement, pour rendre nos utilisateurs heureux.

     // withdLoading.js
    importer React à partir de 'react';
    fonction WithLoading (Component) {
      fonction de retour WihLoadingComponent ({isLoading, ... props}) {
        if (! isLoading) return ;
        return 

    Attendez, la récupération des données peut prendre un certain temps.

    ; }; } exporter WithLoading par défaut;

    Cela afficherait le texte «Attendez, la récupération des données peut prendre un certain temps» lorsque l'application récupère toujours des données et que les accessoires sont injectés dans l'état. Nous utilisons isLoading pour déterminer si le composant doit être rendu.

    Maintenant, dans votre fichier App.js vous pouvez passer la logique de chargement . à WithLoading sans vous en soucier dans votre List .

     import React from 'react';
    importer la liste à partir de './components/List.js';
    importer WithLoading depuis './components/withLoading.js';
    const ListWithLoading = WithLoading (List);
    classe App étend React.Component {
      état = {
    {
      };
      componentDidMount () {
        this.setState ({loading: true});
        fetch (`https: // api.github.com / users / hacktivist123 / repos`)
          .then ((json) => json.json ())
          .then ((repos) => {
            this.setState ({chargement: faux, repos: repos});
          });
      }
      render () {
        revenir (
          
        );
      }
    }
    exporter l'application par défaut;
    

    Le code ci-dessus est l'ensemble de notre application. Décomposons-le pour voir ce qui se passe.

     La ​​classe App étend React.Component {
      état = {
        chargement: faux,
        repos: null,
      };
      componentDidMount () {
        this.setState ({loading: true});
        fetch (`https: // api.github.com / users / hacktivist123 / repos`)
          .then ((json) => json.json ())
          .then ((repos) => {
            this.setState ({chargement: faux, repos: repos});
          });
      }
    

    Tout ce que nous faisons ici est de créer un composant de classe nommé App () puis d'initialiser l'état avec deux propriétés, chargement: false, et repos: null, . L'état initial de chargement est faux tandis que l'état initial de repos est également nul .

    Ensuite, lorsque notre composant est en train de monter, nous définissons le état de la propriété chargeant sur true et faites immédiatement une demande de récupération à l'URL de l'API qui contient les données dont nous avons besoin pour remplir notre composant List . Une fois la demande terminée, nous définissons l'état chargeant sur faux et remplissons l'état repos avec les données que nous avons extraites de la demande API.

     const ListWithLoading = WithLoading (List);
    

    Ici, nous créons un nouveau composant nommé ListWithLoading et passons le WithLoading HOC que nous avons créé ainsi que le composant List List.

     () {
        revenir (
          
        );
      }
    

    Ci-dessus, nous affichons le composant ListWithLoading qui a été suralimenté par le WithLoading HOC que nous avons créé, ainsi que le composant List . En outre, nous transmettons la valeur de l'état de chargement et la valeur de l'état de repos comme accessoires au composant.

    Étant donné que la page tente toujours d'extraire des données de l'API, notre HOC afficher le texte suivant dans le navigateur.

    État de chargement de l'application ( Grand aperçu )

    Lorsque le chargement est terminé et que les accessoires ne sont plus dans un état vide, les dépôts seront rendus à l'écran .

    État terminé du chargement de l'application ( Grand aperçu )

    Composants de rendu conditionnel

    Supposons que nous ayons un composant qui ne doit être rendu que lorsqu'un utilisateur est authentifié - il s'agit d'un composant protégé. Nous pouvons créer un HOC nommé WithAuth () pour envelopper ce composant protégé, puis effectuer une vérification dans le HOC qui ne rendra que ce composant particulier si l'utilisateur a été authentifié.

    Une base ] withAuth () HOC, selon l'exemple ci-dessus, peut s'écrire comme suit:

     // withAuth.js
    importer React à partir de "react";
    fonction d'exportation avecAuth (Component) {
        classe de retour AuthenticatedComponent étend React.Component {
            isAuthenticated () {
                renvoyer this.props.isAuthenticated;
            }
    
            / **
             * Rendu
             * /
            render () {
                const loginErrorMessage = (
                    
    Veuillez vous connecter pour voir cette partie de la demande.
    ); revenir (
    {this.isAuthenticated === true? : loginErrorMessage}
    ); } }; } exporter par défaut avecAuth;

    Le code ci-dessus est un HOC nommé withAuth . Il prend essentiellement un composant et renvoie un nouveau composant, nommé AuthenticatedComponent qui vérifie si l'utilisateur est authentifié. Si l'utilisateur n'est pas authentifié, il renvoie le composant loginErrorMessage ; si l'utilisateur est authentifié, il renvoie le composant encapsulé.

    Remarque: this.props.isAuthenticated doit être défini à partir de la logique de votre application. (Sinon, utilisez react-redux pour le récupérer à partir de l'état global.)

    Pour utiliser notre HOC dans un composant protégé, nous l'utiliserions comme ceci:

     // MyProtectedComponent.js
    importer React à partir de "react";
    importer {withAuth} à partir de "./withAuth.js";
    
    la classe d'exportation MyProectedComponent étend React.Component {
        / **
         * Rendu
         * /
        render () {
            revenir (
                
    Ceci n'est visible que par les utilisateurs authentifiés.
    ); } } // Enveloppez maintenant MyPrivateComponent avec la fonction requireAuthentication exporter par défaut avecAuth (MyPrivateComponent);

    Ici, nous créons un composant qui n'est visible que par les utilisateurs authentifiés. Nous enveloppons ce composant dans notre avecAuth HOC pour protéger le composant contre les utilisateurs qui ne sont pas authentifiés.

    Fournir des composants avec un style spécifique

    Poursuivant le cas d'utilisation ci-dessus, en fonction de l'état de l'interface utilisateur dont vous obtenez le HOC, vous pouvez rendre des styles spécifiques pour des états d'interface utilisateur spécifiques. Par exemple, si le besoin se fait sentir à plusieurs endroits pour des styles comme backgroundColor fontSize et ainsi de suite, ils peuvent être fournis via un HOC en enveloppant le composant avec un composant qui injecte simplement les accessoires avec le className spécifique .

    Prenez un composant très simple qui rend «bonjour» et le nom d'une personne. Il faut un nom prop et un autre accessoire qui peut affecter le XML JavaScript rendu (JSX).

     // Un composant simple
    const HelloComponent = ({nom, ... otherProps}) => (
     
    Bonjour {name}! / Div> );

    Créons un HOC nommé withStyling qui ajoute du style au texte "hello".

     const withStyling = (BaseComponent) => (props) => (
      
    );
    

    Afin d'utiliser le HOC sur notre HelloComponent nous enroulons le HOC autour du composant. Nous créons un composant pur, nommé EnhancedHello et affectons le HOC et notre HelloComponent comme ceci:

     const EnhancedHello = withStyling (HelloComponent);
    

    Pour modifier notre HelloComponent nous rendons le composant EnhancedHello :

     
    

    Maintenant, le texte de notre HelloComponent devient ceci:

     
    Hello World

    Fournir un composant avec n'importe quel accessoire que vous voulez

    Ceci est un cas d'utilisation populaire pour les HOC. Nous pouvons étudier notre base de code et noter quel accessoire réutilisable est nécessaire entre les composants. Ensuite, nous pouvons avoir un wrapper HOC pour fournir à ces composants l'hélice réutilisable.

    Prenons l'exemple ci-dessus:

     // Un composant simple
    const HelloComponent = ({nom, ... otherProps}) => (
     
    Bonjour {name}!
    );

    Créons un HOC nommé withNameChange qui définit un nom prop sur un composant de base sur "Nouveau nom".

     const withNameChange = (BaseComponent) => (props) => (
      
    );
    

    Afin d'utiliser le HOC sur notre HelloComponent nous enroulons le HOC autour du composant, créons un pur composant nommé EnhancedHello2 et attribuons le HOC et notre HelloComponent comme ceci:

     const EnhancedHello2 = withNameChange (HelloComponent);
    

    Pour modifier notre HelloComponent nous pouvons rendre le composant EnhancedHello comme suit:

     
    

    Maintenant, le texte de notre HelloComponent devient ceci:

     
    Hello New World

    Pour changer le nom de accessoire, tout ce que nous avons à faire est le suivant:

     
    

    Le texte de notre BonjourComposant devient ceci:

     
    Bonjour Shedrack

    Construisons un composant d'ordre supérieur

    Dans cette section, nous allons construire un HOC qui prend un composant qui a un prop prop, puis nous utiliserons le prop name prop dans notre HOC.

    Donc, générez une nouvelle application React avec create-react -app comme ceci:

     npx create-react-app my-app
    

    Une fois généré, remplacez le code de votre fichier index.js par l'extrait de code suivant:

     import React from 'react';
    import {render} de 'react-dom';
    const Bonjour = ({nom}) =>
      

    Bonjour {name}!

    ; fonction withName (WrappedComponent) { la classe de retour étend React.Component { render () { retour ; } }; } const NewComponent = withName (Bonjour); const App = () =>
    ; render (document.getElementById ('root'));

    Une fois que vous avez remplacé le code dans votre fichier index.js vous devriez voir ce qui suit sur votre écran:

    Notre application React ( Grand aperçu )

    Passons en revue l'extrait de code petit à petit.

     const Hello = ({name}) =>
      

    Bonjour {name}!

    ;

    Ici, nous créons un composant fonctionnel qui a un accessoire appelé nom . Dans ce composant fonctionnel, nous rendons le «Bonjour» et la valeur de l'accessoire nom dans une balise h1 . Fonction

     withName (WrappedComponent) {
      la classe de retour étend React.Component {
        render () {
          retour ;
        }
      };
    }
    

    Ci-dessus, nous créons un composant fonctionnel d'ordre supérieur nommé avecName () . Ensuite, nous renvoyons un composant de classe anonyme à l'intérieur qui rend le composant encapsulé dans le HOC. Et nous attribuons une valeur à l'hélice du composant encapsulé.

     const NewComponent = withName (Hello);
    

    Ici, nous créons un nouveau composant nommé NewComponent . Nous utilisons le HOC que nous avons créé et nous lui affectons le composant fonctionnel que nous avons créé au début de la base de code, nommé bonjour .

     const App = () =>
      
    ; render (document.getElementById ('root'));

    Tout ce que nous faisons ci-dessus est de créer un autre composant fonctionnel, nommé App . Il rend le nouveau composant que nous avons mis à niveau avec notre HOC dans une division . Ensuite, nous utilisons la fonction react-dom render pour afficher le composant dans le navigateur.

    C'est tout ce que nous devons faire! Notre fonction withName prend un composant comme argument et renvoie un HOC. Dans quelques mois, si nous décidons de changer les choses, il nous suffit de modifier notre HOC.

    Conclusion

    J'espère que vous avez apprécié ce didacticiel. Vous pouvez en savoir plus sur les composants d'ordre supérieur dans les références répertoriées ci-dessous. Si vous avez des questions, laissez-les dans la section commentaires ci-dessous. Je serai heureux de répondre à chacun.

    Ressources et références

     Éditorial fracassant (ks, ra, il, al)




    Source link