Gancio di useCallbackreazione


Il React useCallbackHook restituisce una funzione di callback memorizzata.

Pensa alla memorizzazione come alla memorizzazione nella cache di un valore in modo che non debba essere ricalcolato.

Questo ci consente di isolare le funzioni ad alta intensità di risorse in modo che non vengano eseguite automaticamente su ogni rendering.

Hook viene eseguito solo quando una delle useCallbacksue dipendenze si aggiorna.

Questo può migliorare le prestazioni.

Gli useCallbacke useMemoHooks sono simili. La differenza principale è che useMemorestituisce un valore memorizzato e useCallbackrestituisce una funzione memorizzata . Puoi saperne di più su useMemo nel capitolo useMemo .


Problema

Uno dei motivi per l'utilizzo useCallbackè impedire il re-rendering di un componente a meno che i suoi oggetti di scena non siano cambiati.

In questo esempio, potresti pensare che il Todoscomponente non verrà riprodotto a meno che la todosmodifica:

Questo è un esempio simile a quello nella sezione React.memo .

Esempio:

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);

Prova a eseguirlo e fai clic sul pulsante di incremento del conteggio.

Noterai che il Todoscomponente esegue nuovamente il rendering anche quando todosnon cambia.

Perché questo non funziona? Stiamo usando memo, quindi il Todoscomponente non dovrebbe essere riprodotto poiché né lo todosstato né la addTodofunzione cambiano quando il conteggio viene incrementato.

Ciò è dovuto a qualcosa chiamato "uguaglianza referenziale".

Ogni volta che un componente esegue nuovamente il rendering, le sue funzioni vengono ricreate. Per questo motivo, la addTodofunzione è effettivamente cambiata.


w3schools CERTIFIED . 2022

Ottieni la certificazione!

Completa i moduli React, fai gli esercizi, fai l'esame e diventa certificato w3schools!!

ISCRIVITI A $95

Soluzione

Per risolvere questo problema, possiamo utilizzare l' useCallbackhook per impedire che la funzione venga ricreata se non necessario.

Utilizzare il useCallbackgancio per evitare che il Todoscomponente venga riprodotto inutilmente:

Esempio:

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);

Ora il Todoscomponente eseguirà nuovamente il rendering solo quando l' todoselica cambia.