0
votes

Quelle est la différence entre useCallback et useMemo

Peut-être ai-je mal compris quelque chose, mais useCallback Hook s'exécute à chaque fois que le rendu se produit.

J'ai passé des entrées - comme deuxième argument à useCallback - des constantes non toujours modifiables - mais le rappel mémorisé renvoyé exécute toujours mes calculs coûteux à chaque rendu (je suis presque sûr - vous pouvez vérifier par vous-même dans l'extrait ci-dessous).

J'ai changé useCallback pour useMemo - et useMemo fonctionne comme prévu - s'exécute lorsque les entrées passées changent. Et mémorise vraiment les calculs coûteux.

Exemple en direct:

<h1>useCallback vs useMemo:</h1>
<div id="app">Loading...</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
'use strict';

const { useState, useCallback, useMemo } = React;

const neverChange = 'I never change';
const oneSecond = 1000;

function App() {
  const [second, setSecond] = useState(0);
  
  // This 👇 expensive function executes everytime when render happens:
  const calcCallback = useCallback(() => expensiveCalc('useCallback'), [neverChange]);
  const computedCallback = calcCallback();
  
  // This 👇 executes once
  const computedMemo = useMemo(() => expensiveCalc('useMemo'), [neverChange]);
  
  setTimeout(() => setSecond(second + 1), oneSecond);
  
  return `
    useCallback: ${computedCallback} times |
    useMemo: ${computedMemo} |
    App lifetime: ${second}sec.
  `;
}

const tenThousand = 10 * 1000;
let expensiveCalcExecutedTimes = { 'useCallback': 0, 'useMemo': 0 };

function expensiveCalc(hook) {
  let i = 0;
  while (i < tenThousand) i++;
  
  return ++expensiveCalcExecutedTimes[hook];
}


ReactDOM.render(
  React.createElement(App),
  document.querySelector('#app')
);


0 commentaires

4 Réponses :


3
votes

useMemo est destiné à exécuter la fonction et à renvoyer une valeur au moment du rendu du composant (en supposant que l'une des dépendances a changé). useCallback est destiné à renvoyer une fonction (mémorisée) au moment du rendu, mais n'appelle pas encore la fonction; généralement, vous passez simplement cette fonction à un paramètre onClick ou quelque chose comme ça.

Vous pouvez les utiliser de manière interchangeable s'ils sont appelés correctement, par exemple avoir useMemo renvoyer une fonction équivaut à useCallback , ou utiliser useCallback et appeler la fonction retournée est similaire à useMemo


0 commentaires

3
votes

useMemo() rend la fonction exécutée uniquement lorsque les entrées changent. Sinon, il renvoie le résultat mémorisé (mis en cache). Il n'est suggéré d'utiliser useMemo() pour les fonctions impliquant des calculs complexes (plus de complexité en temps) car il y a un coût à exécuter useMemo()

useCallback() empêche la nouvelle instance de la fonction (je veux dire que la fonction est redéfinie) en cours de création sur chaque rendu et empêche ainsi le rendu des composants enfants si nous leur passons la fonction comme accessoires


0 commentaires

0
votes

De nos jours (25.05.2020), useCallback et useMemo peuvent être utilisés de manière interchangeable:

const fn = () => { function code }

const fn1 = React.useCallback(fn, deps)
const fn2 = React.useMemo(() => fn, deps)

Dans les deux cas, fn1 et fn2 sont enregistrés entre différents rendus. La différence est que useCallback pourrait être amélioré à l'avenir où il renvoie toujours la même fonction et la relaie à la dernière fonction qui lui est passée.

J'ai écrit à ce sujet ici .


0 commentaires

0
votes

Dans votre exemple, votre fonction expensiveCalc dans le useCallback sera exécuté à chaque rendu parce que vous appelez la fonction memoized directement en dessous du useCallback sur chaque rendu.

useCallback mémorisera et retournera la fonction réelle, donc même si la fonction est mémorisée, elle sera toujours exécutée chaque fois que vous l'appelez.

Dans l'exemple, c'est essentiellement ce qui se passe:

const calcResult = expensiveCalc('useCallback');
function App() {

Dans votre cas, vous ne devez pas utiliser useCallback .

Si possible, déplacez la fonction coûteuse en dehors de votre composant de réaction et exécutez-la également à l'extérieur. par exemple:

const calcCallback = () => expensiveCalc('useCallback');
const computedCallback = calcCallback();

Si, pour une raison quelconque, cela n'est pas possible, c'est ici que useMemo s'intègre.

useMemo mémorisera la valeur renvoyée par votre fonction et la conservera entre les rendus jusqu'à ce que vos dépendances changent.

Cela signifie que si vous ne souhaitez pas exécuter une fonction coûteuse sur chaque rendu et que vous voulez uniquement la valeur, alors déplacez-la hors de la portée du composant useMemo ou utilisez useMemo .

Pour plus de détails et d'informations sur les deux hooks, vous pouvez en savoir plus sur cet article: Quelle est la différence entre useMemo et useCallback?


0 commentaires