Un regard plus approfondi sur les crochets React les plus populaires
Pawel Rybczynski
Software Engineer
Au cours de nombreux entretiens, j'ai remarqué que même les programmeurs expérimentés avaient du mal à distinguer les Hooks, sans parler de leurs capacités plus avancées. Je vais donc essayer d'expliquer dans cet article comment utiliser les crochets.
Les points les plus importants à retenir concernant les crochets :
ils ne peuvent être utilisés que dans les composants de fonction - les composants de classe ont leur propre cycle de vie ;
ils commencent toujours par utiliser;
vous pouvez utiliser autant de crochets que vous le souhaitez, mais vous devez vous rappeler que leur utilisation a un impact sur les performances globales ;
ils doivent être exécutés dans le même ordre à chaque rendu... mais pourquoi ? Prenons un exemple :
Dans un premier temps, vous recevrez un avertissement d'eslint :
<code>srcFunctionComponent.js
Ligne 11:5 : React Le crochet "useEffect" est appelé conditionnellement. <strong>React Crochets</strong> doit être appelé dans le même ordre dans chaque composant render .eslintreact-hooks/rules-of-hooks
Comme vous pouvez le voir, il s'agit seulement d'un avertissement eslint, vous pouvez donc le désactiver en ajoutant une commande ci-dessous en haut du fichier Composant de fonction
/* eslint-disable react-hooks/rules-of-hooks */
et cela fonctionnera mais seulement jusqu'à ce que nous remplissions la condition qui exécute notre Hook. La prochaine chose que nous verrons est cette erreur.
Erreur non corrigée : A rendu plus de crochets que lors du rendu précédent.
React 5
FunctionComponent FunctionComponent.js:11
React 12
unstable_runWithPriority scheduler.development.js:468
React 17
js index.js:7
js main.chunk.js:905
Webpack 7
react-dom.development.js:15162
Pourquoi cela se produit-il ? React s'appuie sur l'ordre dans lequel les crochets sont appelés, car React ne saurait pas ce qu'il faut renvoyer pour useEffect parce qu'il n'y a pas de crochet de ce type dans la ligne à vérifier.
N'oubliez pas qu'eslint est un outil puissant, qui nous aide à détecter un grand nombre de bogues et d'erreurs potentiels. Désactiver ses avertissements est une chose dangereuse, vérifiez toujours si le fait d'ignorer l'avertissement peut provoquer un plantage de l'application.
useState
Vous savez sans doute à quoi ça ressemble 😉
const [value, setValue] = useState(0) ;
Vous avez donc 4 éléments : l'état (valeur réactive), la fonction de mise à jour (setter), le crochet actuel (fonction) et la valeur initiale optionnelle. Pourquoi un tableau est-il retourné ? Parce que nous pouvons le restructurer comme nous le souhaitons.
Je voudrais maintenant me concentrer sur le dernier élément : la valeur initiale. Il existe deux façons de transmettre l'état initial :
Par une valeur codée en dur ou autre - qui sera appelée à chaque rendu
const [value, setValue] = useState(0) ;
Par une version de fonction. C'est vraiment utile si nous voulons exécuter l'état initial une seule fois, lors du tout premier rendu. Peut-être avez-vous besoin de faire beaucoup de calculs complexes pour recevoir l'état initial ? Cela diminuera agréablement le coût des ressources, yay !
Une autre chose qui peut créer des bogues dans le flux de l'application : vous savez probablement comment mettre à jour un état, n'est-ce pas ?
setValue(1) ;
D'accord, mais que faire si je veux mettre à jour l'état sur la base d'un état précédent ?
setValue(valeur + 1) ;
Oui... Mais non... Et si vous essayez d'appeler la fonction setter deux fois, l'une après l'autre ? La méthode recommandée pour mettre à jour un état sur la base de l'état précédent est d'utiliser une fonction. Elle garantit que vous faites référence à l'état précédent
setValue((prevState) => prevState + 1) ;
// avec des objets :
setUser((prevState) => ({ ...prevState, lastName : "Brzeczyszczykiewicz" })) ;
useEffect
Ce Hook prend 2 arguments (le second est optionnel) et nous l'utilisons pour gérer les effets de bord. Et selon ce que nous passons comme second argument, le Hook sera appelé différemment :
sans deuxième argument - chaque rendu
useEffect(() => {
doSomething() ;
}) ;
tableau vide - uniquement lors du premier rendu
useEffect(() => {
doSomething() ;
}, []) ;
avec des dépendances - à chaque fois que la valeur du tableau de dépendances change
Avec useEffect, nous pouvons utiliser ce que l'on appelle le nettoyage. À quoi cela sert-il ? C'est très utile, mais je pense que c'est mieux pour nettoyer les écouteurs d'événements. Disons que vous voulez créer un écouteur d'événement qui dépend d'un certain état. Vous ne voulez pas ajouter un nouvel écouteur d'événement à chaque changement d'état, car après quelques rendus, il y aura tellement d'écouteurs que cela affectera les performances de l'application. Une bonne façon d'éviter cela est d'utiliser la fonctionnalité de nettoyage. Comment faire ? Il suffit d'ajouter une fonction de retour à la fonction useEffect.
Parce que c'est à l'intérieur du hook useEffect, le return est appelé en fonction du tableau de dépendance - à chaque rendu, seulement au premier rendu, ou quand la valeur dans le tableau de dépendance change. Mais lorsque le composant est démonté, le nettoyage sera appelé sur le second argument quoi qu'il arrive. Le retour code est appelé avant le code réel de Hook. C'est très logique - d'abord nettoyer l'ancien, puis créer un nouveau. N'est-ce pas ?
Ainsi, vous recevrez tout d'abord un supprimer message, puis Ajouter.
Il y a une chose à laquelle il faut faire attention lorsque l'on utilise useEffect et du code asynchrone à l'intérieur de celui-ci. Regardez le code ci-dessous :
Au début, tout semble normal. Vous récupérez des données, et lorsque les données arrivent, vous mettez à jour l'état. Et voici le piège :
Il arrive que vous receviez un tel avertissement : Impossible d'effectuer une mise à jour d'état React sur un composant non monté. Il s'agit d'une opération sans intérêt, mais elle indique une fuite de mémoire dans votre application. Pour y remédier, annulez tous les abonnements et toutes les tâches asynchrones dans une fonction de nettoyage useEffect.
La raison est que le composant peut être démonté entre-temps, mais l'application essaiera toujours de mettre à jour l'état de ce composant après que la promesse ait été tenue. Comment résoudre ce problème ? Vous devez vérifier si le composant existe.
Note : Il existe un Hook très similaire => useLayoutEffect() - le callback s'exécute après le rendu du composant mais avant que le dom ne soit visuellement mis à jour. C'est utile lorsque vous travaillez avec getBoundingClientRect(), mais vous devriez utiliser useEffect par défaut. Pourquoi ? Parce que cela peut bloquer les mises à jour visuelles - lorsque vous avez un code complexe à l'intérieur de votre effet Hook.
useContext
A quoi cela sert-il ? Partager des données sans passer d'accessoires. Il se compose des éléments suivants :
Contexte créé - données
Fournisseur de contexte - fournir un contexte à tous les enfants
Valeur transmise - données que vous souhaitez partager
Hook - pour lire les données partagées
const user = {
name : "Adam",
nom de famille : "Kowalski",
} ;
export const UserContext = createContext(user) ;
;
```
Dans child, vous devez importer le contexte et appeler le hook useContext et passer ce contexte comme argument.
import { UserContext } from "./App" ;
const { name } = useContext(UserContext) ;
return <h1>Bonjour {nom}<>
```
Voilà. Ça a l'air cool. Principalement pour passer des données globales comme les thèmes, etc. Il n'est pas recommandé de l'utiliser pour des tâches avec des changements très dynamiques.
Bien sûr, nous pouvons créer un fournisseur de contexte personnalisé et un Hook personnalisé pour réduire le nombre de références... mais je traiterai des Hooks personnalisés dans le prochain article.
useReducer
Il nous permet de gérer l'état et d'effectuer un nouveau rendu lorsque l'état change - comme useState. Il est similaire au redux reducer. Il est meilleur que useState lorsque la logique d'état est plus compliquée.
À quoi cela sert-il ? Il peut être utilisé lorsque nous voulons réinitialiser l'état à sa valeur initiale. Vous trouverez ci-dessous un exemple intéressant :
// Parent
// Enfant
function init(initialNumber) {
return { number : initialNumber } ;
}
function reducer(state, action) {
switch (action.type) {
case "change" :
return { number : Math.random() } ;
case "reset" :
return init(action.payload) ;
par défaut :
throw new Error() ;
}
}
export default function ChildComponent({ getFactorial }) {
const [state, dispatch] = useReducer(reducer, initialNumber, init) ;
return (
<>
<h2>Numéro : {état.numéro}</h2>
<button
onclick="{()" > dispatch({ type : "reset", payload : initialNumber })}
>
Remise à zéro
</button>
<button onclick="{()" > dispatch({ type : "change" })}>Dessiner</button>
</>
);
}
Numéro : {état.numéro}
useCallback
Quand l'utiliser ? Lorsque nous voulons obtenir une égalité référentielle (réduisant ainsi le nombre de fonctions créées). Ce crochet renvoie la fonction, contrairement à useMemo qui renvoie la valeur.
Exemple : Créer une fonction dans le composant parent et la transmettre par l'intermédiaire de props
Il affichera un journal dans la console à chaque rendu ! Même si les valeurs à l'intérieur de l'élément getSquaredValue() n'a pas changé. Mais nous pouvons éviter cela en enveloppant cette fonction dans useCallback
Elle n'est pas neutre en ce qui concerne les coûts des ressources - useMemo doit être appelée à chaque rendu, elle enregistre la valeur en mémoire et la compare (surcharge de mémoire),
utilise la mémorisation - technique d'optimisation, forme spécifique de mise en cache.
Vous ne devez l'utiliser que dans deux cas de figure :
Si vous voulez éviter d'appeler un code complexe à chaque rendu ;
Si vous souhaitez obtenir l'égalité référentielle.
Examinons de plus près le second cas. Nous voulons utiliser useEffect avec un objet comme dépendance. Parce que les objets sont comparés par leur référence, useEffect sera appelé à chaque rendu. Pour éviter cela, nous pouvons combiner useEffect avec useMemo pour mémoriser ces objets et ensuite passer ces objets mémorisés au tableau de dépendance. Petit exemple :
L'objet 'hobbit' fait changer les dépendances du hook useEffect (ligne 49) à chaque rendu. Déplacez-le à l'intérieur du callback useEffect. Alternativement, intégrez l'initialisation de 'hobbit' dans son propre crochet useMemo ().eslintreact-hooks/exhaustive-deps
La chose la plus importante : useRef ne déclenche pas de nouveau rendu (comme useState) parce qu'il n'est pas connecté au cycle de rendu - il conserve la même référence entre les rendus.
const ref = useRef(0) ;
Pour appeler la valeur sauvegardée, vous devez utiliser une propriété courante (ref est un objet) - ref.current
Le deuxième cas pour lequel nous pouvons utiliser ce crochet est pour référencer des éléments à l'intérieur du HTML. Chaque élément possède un attribut ref. Ainsi, nous pouvons gérer le focus, les événements, etc.
Dans le troisième cas, nous pouvons utiliser les refs pour gérer les composants non contrôlés. Vous trouverez plus d'informations à ce sujet dans react docs, mais en résumé, cela ressemble à ceci :
Comme vous pouvez le voir, il n'y a pas de gestionnaire d'événement, il se contente de mémoriser la valeur saisie. C'est très pratique pour gérer des formulaires basiques lorsque vous voulez juste lire les valeurs sauvegardées lorsque vous en avez besoin (comme lors de la soumission).
Bonus : C`est idéal lorsque vous avez besoin de vous souvenir des valeurs d`état précédentes. Vous pouvez utiliser pour cela le crochet useEffect, en passant simplement l'état à la référence.
Comme vous pouvez le constater, les crochets ne sont pas si évidents. Nous pouvons les combiner pour résoudre de nombreux problèmes. L'étude de ce sujet vous sera certainement très utile.
Il existe également des crochets personnalisés...
En conclusion, Crochets React ont révolutionné la façon dont les Développeurs React Approche de la construction applications web . En offrant un moyen plus intuitif et plus efficace de gérer l'état et le cycle de vie des composants fonctionnels, les crochets sont devenus une partie intégrante des systèmes de gestion de l'information. Développement React .
Que vous soyez un développeur chevronné ou que vous débutiez avec React, il est essentiel de comprendre les crochets les plus populaires et leurs cas d'utilisation. Avec des crochets tels que useState, useEffect, useContext, et bien d'autres encore, il est essentiel de comprendre les crochets les plus populaires et leurs cas d'utilisation, Composants React peuvent être construits avec un code plus propre et plus réutilisable. En outre, la possibilité de créer des crochets personnalisés permet aux développeurs d'encapsuler et de partager la logique entre plusieurs composants, ce qui favorise la réutilisation du code et la modularité. Alors que React continue d'évoluer et d'introduire de nouvelles fonctionnalités, les crochets joueront sans aucun doute un rôle central dans l'exploitation du plein potentiel du cadre.
Ainsi, que vous travailliez sur une petite application fonctionnelle ou sur une application web à grande échelle, l'adoption de la Crochets React améliorera votre flux de travail de développement et ouvrira une pléthore de possibilités pour la création de systèmes d'information robustes et riches en fonctionnalités. Applications React .