useCallback |
Utilise un appel en arrière-plan |
|---|---|
| Railo | |
Syntaxe
| const cachedFn = useCallback(fn, dependencies) |
Description
useCallback est un crochet React permettant d'entreposer en cache la définition d'une fonction entre deux rendus.
Remarques
- Le compilateur React mémorise automatiquement les valeurs et les fonctions, ce qui permet de réduire le recours aux appels manuels de la fonction useCallback. Vous pouvez donc utiliser le compilateur pour gérer la mémorisation de manière automatique.
Référence
| useCallback(fn, dependencies) |
Appelez useCallback au niveau supérieur de votre composant pour mettre en cache la définition d'une fonction entre les différents rendus :
Voir d'autres exemples ci-dessous.
Paramètres
| Nom | Description |
|---|---|
| fn | Il s'agit de la fonction dont vous souhaitez entreposer la valeur en cache. Cette fonction peut prendre n'importe quel paramètre et retourner n'importe quelle valeur. React vous renverra (mais ne l'appellera pas) cette fonction lors du premier rendu. Lors des rendus suivants, React vous renverra la même fonction si les dépendances n'ont pas changé depuis le dernier rendu. Sinon, il vous renverra la fonction que vous avez fournie lors du rendu actuel et la stockera en mémoire pour une réutilisation ultérieure. React n'appellera pas votre fonction. Elle vous est simplement fournie afin que vous puissiez décider quand et si vous souhaitez l'appeler. |
| dependencies | Cette liste répertorie toutes les valeurs réactives utilisées dans le code de la fonction. Les valeurs réactives comprennent les propriétés, l'état et toutes les variables et fonctions déclarées directement dans le corps de la composante. Si votre outil de vérification de code est configuré pour React, il vérifiera que chaque valeur réactive est correctement déclarée comme dépendance. La liste des dépendances doit contenir un nombre fixe d'éléments et être écrite de manière concise, comme [dep1, dep2, dep3]. React comparera chaque dépendance à sa valeur précédente à l'aide de l'algorithme de comparaison Object.is. |
Valeur de retour
Lors du premier rendu, useCallback renvoie la fonction `fn` que vous avez passée en paramètre.
Lors des rendus suivants, il renverra soit la fonction `fn` précédemment entreposée (si les dépendances n'ont pas changé), soit la fonction `fn` que vous avez passée lors du rendu actuel.
Remarques
- useCallback est un crochet ; vous ne pouvez donc l'appeler qu'au niveau supérieur de votre composante ou de vos propres crochets. Il est impossible de l'appeler à l'intérieur d'une boucle ou d'une condition. Si vous avez besoin de cette fonctionnalité, créez une nouvelle composante et déplacez le state à l'intérieur.
- React ne supprimera la fonction mise en cache que dans des cas spécifiques. Par exemple, en développement, React supprime le cache lorsque vous modifiez le fichier de votre composante. En production comme en développement, React supprimera le cache si votre composant est suspendu lors du montage initial. À l'avenir, React pourrait ajouter des fonctionnalités exploitant cette suppression du cache (par exemple, si React intègre le support des listes virtualisées, il serait logique de supprimer le cache des éléments hors du champ de visualisation). Ce comportement devrait correspondre à vos attentes si vous utilisez useCallback pour optimiser les performances. Sinon, une variable de state ou une référence pourrait être plus appropriée.
Utilisation
Optimisation des performances de rendu
Lors de l'optimisation des performances de rendu, il peut être nécessaire de mettre en cache les fonctions que vous transmettez aux composantes enfants. Voyons d'abord la syntaxe pour ce faire, puis les cas d'utilisation.
Pour mettre en cache une fonction entre les différents rendus de votre composant, encapsulez sa définition dans le crochet useCallback :
- import { useCallback } from 'react';
-
- function ProductPage({ productId, referrer, theme }) {
- const handleSubmit = useCallback((orderDetails) => {
- post('/product/' + productId + '/buy', {
- referrer,
- orderDetails,
- });
- }, [productId, referrer]);
- // ...
Vous devez passer deux éléments à la fonction useCallback :
- La définition de la fonction que vous souhaitez conserver en mémoire entre les rendus.
- Une liste des dépendances, comprenant toutes les valeurs de la composante utilisées à l'intérieur de cette fonction.
Lors du premier rendu, la fonction retournée par useCallback sera la même que celle que vous avez passée en paramètre.
Lors des rendus suivants, React comparera les dépendances avec celles passées lors du rendu précédent. Si aucune dépendance n'a changé (comparaison effectuée avec Object.is), useCallback retournera la même fonction. Sinon, useCallback retournera la fonction passée lors de ce rendu.
Autrement dit, useCallback entrepose la fonction en mémoire entre les rendus successifs, jusqu'à ce que ses dépendances changent.
Prenons un exemple pour illustrer son utilité.
Supposons que vous transmettiez une fonction handleSubmit de la composante ProductPage au composante ShippingForm :
Vous avez remarqué que le changement de thème provoque un bref blocage de l'application. En revanche, si vous supprimez la composante <ShippingForm /> de votre code JSX, l'application fonctionne plus rapidement. Cela suggère qu'il serait judicieux d'optimiser le composante ShippingForm.
Par défaut, lorsque React re-rendu un composant, il re-rendu également tous ses enfants de manière récursive. Ainsi, lorsque ProductPage est re-rendu avec un nouveau thème, le composant ShippingForm est lui aussi re-rendu. Ce comportement est acceptable pour les composants dont le re-rendu ne nécessite pas de calculs complexes. Cependant, si vous constatez que le re-rendu de ShippingForm est lent, vous pouvez empêcher son re-rendu inutile en l'encapsulant dans la fonction memo() lorsque ses propriétés restent inchangées.
- import { memo } from 'react';
-
- const ShippingForm = memo(function ShippingForm({ onSubmit }) {
- // ...
- });
Grâce à ce changement, le composant ShippingForm omettra le re-rendu si toutes ses propriétés sont identiques à celles du rendu précédent. C'est à ce moment-là que le stockage en cache d'une fonction devient important ! Prenons l'exemple suivant : vous avez défini la fonction handleSubmit sans utiliser useCallback :
- function ProductPage({ productId, referrer, theme }) {
- // À chaque changement de thème, cette fonction sera différente...
- function handleSubmit(orderDetails) {
- post('/product/' + productId + '/buy', {
- referrer,
- orderDetails,
- });
- }
-
- return (
- <div className={theme}>
- {/* ... Ainsi, les propriétés de ShippingForm seront toujours différentes, et la composante sera donc toujours redessiné. */}
- <ShippingForm onSubmit={handleSubmit} />
- </div>
- );
- }
En JavaScript, une fonction définie avec la syntaxe () {} ou () => {} crée toujours une fonction différente, de la même manière qu'un objet créé avec la notation {} est toujours un nouvel objet. Normalement, cela ne pose pas de problème, mais cela signifie que les propriétés de la composante ShippingForm ne seront jamais identiques, ce qui rend l'optimisation par mémoire cache (memoization) inopérante. C'est là que la fonction useCallback s'avère utile :
- function ProductPage({ productId, referrer, theme }) {
- // Indiquez à React de mettre en cache votre fonction entre les différents rendus...
- const handleSubmit = useCallback((orderDetails) => {
- post('/product/' + productId + '/buy', {
- referrer,
- orderDetails,
- });
- }, [productId, referrer]); // ...donc, tant que ces dépendances ne changent pas...
-
- return (
- <div className={theme}>
- {/* ...La composante ShippingForm recevra les mêmes propriétés et pourra ainsi éviter le re-rendu inutile. */}
- <ShippingForm onSubmit={handleSubmit} />
- </div>
- );
- }
En enveloppant la fonction handleSubmit dans useCallback, vous vous assurez qu'elle reste la même lors des re-rendus (jusqu'à ce que les dépendances changent). Il n'est pas nécessaire d'utiliser useCallback pour toute fonction ; son utilisation doit être justifiée. Dans cet exemple, l'intérêt est de la passer à une composante enveloppé dans memo, ce qui permet d'éviter un re-rendu inutile. D'autres cas d'utilisation de useCallback sont décrits plus loin sur cette page.
Note
N'utilisez useCallback que pour optimiser les performances. Si votre code ne fonctionne pas sans, identifiez et corrigez d'abord le problème. Vous pourrez ensuite réintroduire useCallback.