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