Ganchos de useEffectreacción


El useEffectgancho le permite realizar efectos secundarios en sus componentes.

Algunos ejemplos de efectos secundarios son: obtención de datos, actualización directa del DOM y temporizadores.

useEffectacepta dos argumentos. El segundo argumento es opcional.

useEffect(<function>, <dependency>)


Usemos un temporizador como ejemplo.

Ejemplo:

Úselo setTimeout()para contar 1 segundo después del renderizado inicial:

import { useState, useEffect } from "react";
import ReactDOM from "react-dom";

function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setTimeout(() => {
      setCount((count) => count + 1);
    }, 1000);
  });

  return <h1>I've rendered {count} times!</h1>;
}

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

¡¡Pero espera!! ¡Sigo contando aunque solo debería contar una vez!

useEffectse ejecuta en cada render. Eso significa que cuando cambia el conteo, ocurre un renderizado, que luego desencadena otro efecto.

Esto no es lo que queremos. Hay varias formas de controlar cuándo se presentan los efectos secundarios.

Siempre debemos incluir el segundo parámetro que acepta una matriz. Opcionalmente, podemos pasar dependencias a useEffectesta matriz.

1. No pasó ninguna dependencia:

useEffect(() => {
  //Runs on every render
});

2. Una matriz vacía:

useEffect(() => {
  //Runs only on the first render
}, []);

3. Props o valores de estado:

useEffect(() => {
  //Runs on the first render
  //And any time any dependency value changes
}, [prop, state]);

Entonces, para solucionar este problema, solo ejecutemos este efecto en el renderizado inicial.

Ejemplo:

Solo ejecute el efecto en el renderizado inicial:

import { useState, useEffect } from "react";
import ReactDOM from "react-dom";

function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setTimeout(() => {
      setCount((count) => count + 1);
    }, 1000);
  }, []); // <- add empty brackets here

  return <h1>I've rendered {count} times!</h1>;
}

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

Ejemplo:

Aquí hay un ejemplo de un useEffectHook que depende de una variable. Si la countvariable se actualiza, el efecto se ejecutará nuevamente:

import { useState, useEffect } from "react";
import ReactDOM from "react-dom";

function Counter() {
  const [count, setCount] = useState(0);
  const [calculation, setCalculation] = useState(0);

  useEffect(() => {
    setCalculation(() => count * 2);
  }, [count]); // <- add the count variable here

  return (
    <>
      <p>Count: {count}</p>
      <button onClick={() => setCount((c) => c + 1)}>+</button>
      <p>Calculation: {calculation}</p>
    </>
  );
}

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

Si hay varias dependencias, deben incluirse en la useEffectmatriz de dependencias.


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

Limpieza de efectos

Algunos efectos requieren limpieza para reducir las fugas de memoria.

Se deben desechar los tiempos de espera, las suscripciones, los detectores de eventos y otros efectos que ya no se necesitan.

Hacemos esto incluyendo una función de retorno al final del useEffectHook.

Ejemplo:

Limpie el temporizador al final del useEffectgancho:

import { useState, useEffect } from "react";
import ReactDOM from "react-dom";

function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    let timer = setTimeout(() => {
    setCount((count) => count + 1);
  }, 1000);

  return () => clearTimeout(timer)
  }, []);

  return <h1>I've rendered {count} times!</h1>;
}

ReactDOM.render(<Timer />, document.getElementById("root"));

Nota: Para borrar el temporizador, tuvimos que nombrarlo.


Ponte a prueba con ejercicios

Ejercicio:

¿Qué necesita agregar al segundo argumento de un useEffectHook para limitarlo a ejecutarse solo en el primer renderizado?

import { useState, useEffect } from "react";
import ReactDOM from "react-dom";

function App() {
  const [data, setData] = useState([]);

  useEffect(() => {
    setData(getData())
  }, );

  return <DisplayData data={data} />;
}

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