React hook useEffect выполняется постоянно навсегда / бесконечный цикл

Я пробую новый React Hooks useEffect API и, кажется, работает вечно, в бесконечном цикле! Я хочу только обратный звонок в useEffect бежать один раз. Вот мой код для справки:

Нажмите "Выполнить фрагмент кода", чтобы увидеть, как строка "Выполнить useEffect" печатается на консоли бесконечно.

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>

2 ответа

Решение

Это происходит потому, что useEffect срабатывает после каждого рендера, который является вызовом Counter() функционировать в этом случае без состояния функциональных компонентов. Когда вы делаете setX звонок вернулся из useState в useEffect React отрендерит этот компонент снова и useEffect бежит снова. Это вызывает бесконечный цикл:

Counter()useEffect()setCount()Counter()useEffect() →... (цикл)

Сделать ваш useEffect запустить только один раз, передать пустой массив [] в качестве второго аргумента, как видно из исправленного фрагмента ниже.

Целью второго аргумента является сообщить React, когда изменяется любое из значений в аргументе массива:

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

Вы можете передать любое количество значений в массив и useEffect будет работать только при изменении любого из значений. Передавая пустой массив, мы говорим React не отслеживать какие-либо изменения, только запускать один раз, эффективно имитируя 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>

Узнайте больше об useEffect.

Вы попадаете в бесконечный цикл, поскольку для записанного useEffect не предусмотрена никакая зависимость.

Чтобы избежать бесконечного цикла при использовании перехватчика useEffect, обязательно укажите массив зависимостей, включающий все переменные, от которых зависит эффект.

Например, если вы хотите, чтобы эффект запускался только один раз при монтировании компонента , вы можете передать пустой массив зависимостей следующим образом:

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

Если вы хотите, чтобы эффект запускался при каждом изменении определенной переменной , вы можете включить эту переменную в массив зависимостей:

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

useEffect(() => {
  // effect code here
}, [count])
Другие вопросы по тегам