Crochet de useCallbackréaction


Le React useCallbackHook renvoie une fonction de rappel mémorisée.

Considérez la mémorisation comme la mise en cache d'une valeur afin qu'elle n'ait pas besoin d'être recalculée.

Cela nous permet d'isoler les fonctions gourmandes en ressources afin qu'elles ne s'exécutent pas automatiquement à chaque rendu.

Le useCallbackcrochet ne s'exécute que lorsque l'une de ses dépendances est mise à jour.

Cela peut améliorer les performances.

Les crochets useCallbacket useMemosont similaires. La principale différence est que useMemorenvoie une valeur mémorisée et useCallbackrenvoie une fonction mémorisée . Vous pouvez en savoir plus sur useMemo dans le chapitre useMemo .


Problème

L'une des raisons de l'utiliser useCallbackest d'empêcher un composant de se restituer à moins que ses accessoires n'aient changé.

Dans cet exemple, vous pourriez penser que le Todoscomposant ne sera pas restitué à moins que le todoschangement :

Ceci est un exemple similaire à celui de la section React.memo .

Exemple:

index.js

import { useState } from "react";
import ReactDOM from "react-dom";
import Todos from "./Todos";

const App = () => {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);

  const increment = () => {
    setCount((c) => c + 1);
  };
  const addTodo = () => {
    setTodos((t) => [...t, "New Todo"]);
  };

  return (
    <>
      <Todos todos={todos} addTodo={addTodo} />
      <hr />
      <div>
        Count: {count}
        <button onClick={increment}>+</button>
      </div>
    </>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));

Todos.js

import { memo } from "react";

const Todos = ({ todos, addTodo }) => {
  console.log("child render");
  return (
    <>
      <h2>My Todos</h2>
      {todos.map((todo, index) => {
        return <p key={index}>{todo}</p>;
      })}
      <button onClick={addTodo}>Add Todo</button>
    </>
  );
};

export default memo(Todos);

Essayez de l'exécuter et cliquez sur le bouton d'incrémentation du nombre.

Vous remarquerez que le Todoscomposant restitue même lorsque le todosne change pas.

Pourquoi cela ne fonctionne-t-il pas ? Nous utilisons memo, donc le Todoscomposant ne doit pas être rendu à nouveau puisque ni l' todosétat ni la addTodofonction ne changent lorsque le nombre est incrémenté.

C'est à cause de ce qu'on appelle "l'égalité référentielle".

Chaque fois qu'un composant est restitué, ses fonctions sont recréées. Pour cette raison, la addTodofonction a en fait changé.


w3schools CERTIFIED . 2022

Obtenir une certification!

Complétez les modules React, faites les exercices, passez l'examen et devenez certifié w3schools !!

95 $ S'INSCRIRE

Solution

Pour résoudre ce problème, nous pouvons utiliser le useCallbackcrochet pour empêcher la recréation de la fonction, sauf si nécessaire.

Utilisez le useCallbackcrochet pour empêcher le Todoscomposant de se restituer inutilement :

Exemple:

index.js

import { useState, useCallback } from "react";
import ReactDOM from "react-dom";
import Todos from "./Todos";

const App = () => {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);

  const increment = () => {
    setCount((c) => c + 1);
  };
  const addTodo = useCallback(() => {
    setTodos((t) => [...t, "New Todo"]);
  }, [todos]);

  return (
    <>
      <Todos todos={todos} addTodo={addTodo} />
      <hr />
      <div>
        Count: {count}
        <button onClick={increment}>+</button>
      </div>
    </>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));

Todos.js

import { memo } from "react";

const Todos = ({ todos, addTodo }) => {
  console.log("child render");
  return (
    <>
      <h2>My Todos</h2>
      {todos.map((todo, index) => {
        return <p key={index}>{todo}</p>;
      })}
      <button onClick={addTodo}>Add Todo</button>
    </>
  );
};

export default memo(Todos);

Désormais, le Todoscomposant ne sera restitué que lorsque l' todosaccessoire changera.