Démystifier les Hooks React — useCallback

Commencer
Si vous souhaitez suivre dans votre IDE local, vous pouvez trouver le GitHub Repo ici .
clone
cd client
npm i
npm start
L'égalité référentielle est un concept fondamental à la fois en JavaScript et en informatique dans son ensemble. Commençons donc par une démonstration en action.
J'ai intégré des captures d'écran tout au long de l'article pour faciliter l'utilisation sur mobile. Si vous êtes sur un ordinateur de bureau et que vous l'avez cloné, exécutez-le referentialEquality.js
pour observer la sortie ou jouez simplement avec l'extrait de code JSFiddle intégré ci-dessous.
Lors de l'évaluation si le integer 1
est strictement égal au integer 1
, la console imprime true
. C'est parce que, eh bien… le integer 1
est strictement égal au integer 1
.

Nous voyons le même résultat lors de l'évaluation de deux chaînes.

Évidemment, ce sera toujours le cas pour deux types de données primitifs de même valeur.
Maintenant, qu'en est-il des structures de données ? Par exemple, deux littéraux d'objet avec les mêmes paires clé/valeur ? Qu'en est-il des littéraux d'objet vides ?

Pourquoi cette impression false
? Lorsque vous comparez si ces deux littéraux d'objet sont strictement égaux, JavaScript utilise leurs adresses mémoire respectives .
En d'autres termes, ces deux objets peuvent contenir les mêmes valeurs , mais ils ne font pas référence au même objet . Ils se ressemblent mais occupent deux espaces différents en mémoire .
La même chose s'applique que vous compariez deux littéraux d'objet, deux littéraux de tableau ou deux fonctions !

Pour démontrer cela davantage, nous allons définir une fonction func
, qui renvoie une fonction anonyme qui, à son tour, renvoie quelque chose d'autre ( comme un élément JSX ).

Nous assignerons alors deux fonctions différentes, firstRender
et secondRender
, égales à la valeur renvoyée par func
.

Considérez-le func
comme votre composant fonctionnel React, while firstRender
est une fonction à l'intérieur de celui-ci sur le premier rendu, et secondRender
est une fonction à l'intérieur de celui-ci sur le second rendu.
Même si firstRender
et secondRender
renvoient la même valeur et sont affectés à partir de la même définition, ils n'ont pas d'égalité référentielle . Par conséquent, chaque fois que le composant est rendu, il redéfinit cette fonction.

Malheureusement, en JavaScript, il n'est pas facile d'imprimer ces adresses mémoire comme en Python, mais pour une explication un peu plus approfondie de la référence par rapport à la valeur, jetez un œil à cet article de freeCodeCamp.
Ce sujet peut devenir dense et vous n'avez pas besoin de donner un cours dessus ce soir. Donc, pour l'instant, rappelez-vous simplement:
- type de données primitif
===
type de données primitif - structure de données
!==
structure de données.
Code de démarrage
Après avoir lancé notre application, ouvrez le BookDetails.jsx
composant et réenregistrez. La première chose que nous pouvons remarquer dans notre serveur de développement React est un point commun WARNING
que les jeunes développeurs ont tendance à ignorer. Au fur et à mesure que vous entrez sur le marché du travail et que vous commencez à écrire du code pour la production, vos linters seront encore plus stricts que ce qui est intégré dans create-react-app
. WARNINGS
se transformera en ERRORS
, et certains linters ne vous permettront pas de pousser avant de les traiter ERRORS
.
Alors plutôt que de l'ignorer, voyons comment le traiter.

REMARQUE : vous devrez peut-être d'abord enregistrer à nouveau BookDetails.jsx
pour créer ceWARNING
Si nous creusons dans les React Docs , nous pouvons décoder les solutions proposées semi-confuses WARNING
comme suit :
1. Incluez la définition de la fonction dans le fichier useEffect
.
- Nous ne pouvons pas appeler cette fonction ailleurs à moins de la redéfinir.
- Cela déclenchera
useEffect
chaque changement d'état ou d'accessoires, provoquant parfois un nouveau rendu infini. Et dans notre cas, puisque nous appelons notre fonction de définition d'état après un appel d'API, cela pourrait surcharger notre API avec des demandes de point de terminaison infinies.
- La fonction ne sera pas appelée.
- La première fois que le composant est rendu, il définira notre fonction, qui déclenchera le
useEffect
, ce qui entraînera le rendu du composant, ce qui redéfinira la fonction, ce qui déclenchera leuseEffect
, ce qui entraînera le rendu du composant, ce qui redéfinira la fonction…
La solution la plus simple et préférée serait de "l'inclure", c'est-à-dire de déplacer la getBookDetails
définition de la fonction à l'intérieur du fichier useEffect
. Cela adhère à un principe de programmation orientée objet connu sous le nom d'encapsulation .
Mais disons que nous savons que nous devons appeler la fonction ailleurs. Doit-on le redéfinir plus tard ? Ce n'est pas très sec de notre part.
Modifions notre tableau de dépendances pour inclure notre référence de fonction. Votre useEffect
devrait maintenant ressembler à ceci.

Et getBookDetails
reste défini au-dessus du useEffect
.

Maintenant, nous avons un nouveauWARNING

Entrez le crochet useCallback
En bref, le useCallback
hook vous permet de mettre en cache, ou de "mémoriser", une fonction entre les rendus de votre composant. Il effectue une tâche similaire à useMemo
, dont nous aborderons les nuances dans un autre article.
Si le fond de la situation vous intéresse, vous pouvez en savoir plus dans la documentation React .
Veuillez noter leur avertissement :
Vous ne devriez compter que sur useCallback
une optimisation des performances. Si votre code ne fonctionne pas sans lui, recherchez le problème sous-jacent et corrigez-le d'abord. Ensuite, vous pouvez ajouter useCallback
pour améliorer les performances.
useCallback
Syntaxe
useCallback
La syntaxe de est très similaire à la useEffect
syntaxe de que nous connaissons déjà. Regardez les squelettes de chacun.

La légère différence est qu'avec useEffect
, nous disons à la fonction anonyme d' exécuter notre fonction tandis qu'avec useCallback
, nous attribuons la valeur de retour à une référence à appeler ailleurs.
Utiliser useCallback
Tout d'abord, nous allons importer useCallback
de 'react'
. Plutôt que d'ajouter une nouvelle ligne, il est préférable de la déstructurer avec nos autres importations.

Nous pouvons maintenant affecter getBookDetails
à la valeur renvoyée par un useCallback
appel de fonction.

Ensuite, nous ajoutons toute la syntaxe pour useCallback
. N'oubliez pas votre tableau de dépendances !

Dans notre exemple, nous avons besoin async
avant nos paramètres.

Et enfin, nous ajoutons la logique de notre fonction dans le bloc de code.

Une fois que nous sauvegardons, nous obtenons… un autre WARNING
.

Pourquoi notre tableau de dépendances devrait-il suivre la id
variable ?
Réfléchissons à cela.
- Si la valeur de
id
change,getBookDetails
doit atteindre un point de terminaison différent, React doit donc le redéfinir. La définition de dépendgetBookDetails
littéralement de la valeur de .id

Et enfin, ça y est ! Nous voyons du vert dans notre serveur de développement React. Un linter heureux est un développeur senior heureux. Et un développeur senior heureux est un vous heureux !
Je suis toujours à la recherche de nouveaux amis et collègues. Si vous avez trouvé cet article utile et que vous souhaitez vous connecter, vous pouvez me trouver dans n'importe laquelle de mes maisons sur le Web.
GitHub | Gazouillement | LinkedIn | Site Internet
Ressources
- Égalité référentielle
- Types de données primitifs JavaScript vs structures de données
- Encapsulation
useCallback
- Réagissez aux documents