Gancho de useCallbackreacción


React useCallbackHook devuelve una función de devolución de llamada memorizada.

Piense en la memorización como el almacenamiento en caché de un valor para que no sea necesario volver a calcularlo.

Esto nos permite aislar las funciones que consumen muchos recursos para que no se ejecuten automáticamente en cada renderizado.

El useCallbackHook solo se ejecuta cuando se actualiza una de sus dependencias.

Esto puede mejorar el rendimiento.

Los ganchos useCallbacky useMemoson similares. La principal diferencia es que useMemodevuelve un valor memorizado y useCallbackdevuelve una función memorizada . Puede obtener más información sobre useMemo en el capítulo useMemo .


Problema

Una razón para usarlo useCallbackes evitar que un componente se vuelva a renderizar a menos que sus accesorios hayan cambiado.

En este ejemplo, podría pensar que el Todoscomponente no se volverá a procesar a menos que todoscambie:

Este es un ejemplo similar al de la sección React.memo .

Ejemplo:

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

Intente ejecutar esto y haga clic en el botón de incremento de conteo.

Notará que el Todoscomponente se vuelve a renderizar incluso cuando todosno cambia.

¿Por qué esto no funciona? Estamos usando memo, por lo que el Todoscomponente no debería volver a renderizarse ya que ni el todosestado ni la addTodofunción cambian cuando se incrementa el conteo.

Esto se debe a algo llamado "igualdad referencial".

Cada vez que se vuelve a renderizar un componente, se recrean sus funciones. Debido a esto, la addTodofunción en realidad ha cambiado.


w3schools CERTIFIED . 2022

¡Obtener la certificación!

¡Complete los módulos de React, haga los ejercicios, tome el examen y obtenga la certificación w3schools!

$95 INSCRÍBETE

Solución

Para solucionar esto, podemos usar el useCallbackgancho para evitar que la función se vuelva a crear a menos que sea necesario.

Use el useCallbackgancho para evitar que el Todoscomponente se vuelva a renderizar innecesariamente:

Ejemplo:

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

Ahora el Todoscomponente solo se volverá a renderizar cuando todoscambie la propiedad.