UseEffect de gancho de reacción se ejecuta continuamente para siempre/bucle infinito

3 minutos de lectura

Avatar de usuario de Yangshun Tay
yangshun tay

estoy probando lo nuevo Ganchos de reacción‘s useEffect API y parece seguir ejecutándose para siempre, ¡en un ciclo infinito! Sólo quiero la devolución de llamada en useEffect correr una vez. Aquí está mi código de referencia:

Haga clic en “Ejecutar fragmento de código” para ver que la cadena “Ejecutar useEffect” se imprime infinitamente en la consola.

function Counter() {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    console.log('Run useEffect');
    setCount(100);
  });

  return (
    <div>
      <p>Count: {count}</p>
    </div>
  );
}

ReactDOM.render(<Counter />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

Avatar de usuario de Yangshun Tay
yangshun tay

Esto sucede porque useEffect se activa después de cada render, que es la invocación de la Counter() función en este caso de componentes funcionales. cuando haces un setX llamada devuelta de useState en un useEffectReact renderizará ese componente nuevamente, y useEffect se ejecutará de nuevo. Esto provoca un bucle infinito:

Counter()useEffect()setCount()Counter()useEffect() → … (bucle)

para hacer tu useEffect ejecutar solo una vez, pasar una matriz vacía [] como segundo argumento, como se ve en el fragmento revisado a continuación.

La intención del segundo argumento es decirle a React cuando cambia cualquiera de los valores en el argumento de la matriz:

useEffect(() => {
  setCount(100);
}, [count]); // Only re-run the effect if count changes

Puede pasar cualquier número de valores a la matriz y useEffect solo se ejecutará cuando cambie cualquiera de los valores. Al pasar una matriz vacía, le decimos a React que no rastree ningún cambio, solo se ejecute una vez, simulando de manera efectiva componentDidMount.

function Counter() {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    console.log('Run useEffect');
    setCount(100);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
    </div>
  );
}

ReactDOM.render(<Counter />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

Leer más sobre efecto de uso.

  • Esta es la solución, sin embargo, si está utilizando el react-hooks complemento eslint. Esto sería señalado por el exhaustive-deps regla. Parece que la solución correcta es usar el useCallback gancho, más discusión aquí: github.com/facebook/react/issues/14920#issuecomment-471070149

    – Daniel Cooke

    16 de abril de 2019 a las 14:39

Se está ejecutando en un bucle infinito porque no se proporciona ninguna dependencia al useEffect escrito.

Para evitar un bucle infinito al usar el gancho useEffect, asegúrese de proporcionar una matriz de dependencia que incluya todas las variables de las que depende el efecto

Por ejemplo, si solo desea el efecto para ejecutarse una vez cuando el componente se montapuede pasar una matriz de dependencia vacía como esta:

useEffect(() => {
   // effect code here
}, [])

Si desea que el efecto se ejecute siempre que una variable específica cambiapuede incluir esa variable en la matriz de dependencia:

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

useEffect(() => {
  // effect code here
}, [count])

¿Ha sido útil esta solución?