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
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
- Nous ne modifions ni ne modifions les composants. Nous en créons de nouveaux.
- Un HOC est utilisé pour composer des composants pour la réutilisation de code.
- 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} ; })}
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 retournernull
. Nous effectuons également un rendu conditionnel ici: si la longueur de l'accessoirerepos
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 chargementWithLoading
sans vous en soucier dans votreList
.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,
etrepos: null,
. L'état initial dechargement
estfaux
tandis que l'état initial de repos est égalementnul
.Ensuite, lorsque notre composant est en train de monter, nous définissons le état de la propriété
chargeant
surtrue
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 composantList
. Une fois la demande terminée, nous définissons l'étatchargeant
surfaux
et remplissons l'étatrepos
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 leWithLoading
HOC que nous avons créé ainsi que le composantList
List.() { revenir ( ); }
Ci-dessus, nous affichons le composant
ListWithLoading
qui a été suralimenté par leWithLoading
HOC que nous avons créé, ainsi que le composantList
. En outre, nous transmettons la valeur de l'état dechargement
et la valeur de l'état derepos
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 composantloginErrorMessage
; 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 leclassName 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 notreHelloComponent
comme ceci:const EnhancedHello = withStyling (HelloComponent);
Pour modifier notre
HelloComponent
nous rendons le composantEnhancedHello
:Maintenant, le texte de notre
HelloComponent
devient ceci:Hello WorldFournir 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 unnom
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 notreHelloComponent
comme ceci:const EnhancedHello2 = withNameChange (HelloComponent);
Pour modifier notre
HelloComponent
nous pouvons rendre le composantEnhancedHello
comme suit:Maintenant, le texte de notre
HelloComponent
devient ceci:Hello New WorldPour changer le nom de
Le texte de notre
BonjourComposant
devient ceci:Bonjour ShedrackConstruisons 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 propname
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 = () =>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'accessoirenom
dans une baliseh1
. FonctionwithName (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 = () =>
Tout ce que nous faisons ci-dessus est de créer un autre composant fonctionnel, nommé
App
. Il rend lenouveau composant
que nous avons mis à niveau avec notre HOC dans une divisionrender
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
(ks, ra, il, al)
Source link