N
N
Nikita2020-07-06 08:28:12
React
Nikita, 2020-07-06 08:28:12

Why, when changing the state of a react component in setInterval, the state value is reset to the original one every time?

Code like this

import React, { useState, useEffect } from 'react';

export const App = (): JSX.Element => {
    const [count, setCount] = useState(0);
    
    useEffect(() => {
        setInterval(() => {
            console.log(count);
            setCount(count + 1);
        }, 100);
    }, []);

    return (
        <div>
            { count }
        </div>
    )
}

In the console I see the initial value of count, i.e. - 0, what am I doing wrong?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
N
Nikita, 2020-07-06
@MiiZZo

Explanation from the React documentation:
https://ru.reactjs.org/docs/hooks-faq.html#what-ca...

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

  useEffect(() => {
    const id = setInterval(() => {
      setCount(count + 1); // Этот эффект зависит от переменной состояния `count`
    }, 1000);
    return () => clearInterval(id);
  }, []); //  Баг: `count` не указан в качестве зависимости

  return <h1>{count}</h1>;
}

An empty dependency set [] means that the effect will only run once when the component mounts, not on every re-render. The problem is that inside the setInterval callback, the value of count doesn't change because we created a closure with count set to 0, as we did when the effect callback was executed. Every second this callback calls setCount(0 + 1), so the count never exceeds 1.
Rewriting the list of dependencies as [count] will fix the bug, but it will reset the interval on every change. This behavior may not be desirable. To fix this, we can use a form of functional update of the setState hook that allows you to specify how the state should change without explicitly referring to the current state:
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      setCount(c => c + 1); // ✅ Эта строчка не зависит от внешней переменной `count`
    }, 1000);
    return () => clearInterval(id);
  }, []); // ✅ Наш эффект не использует никаких переменных из области видимости компонента

  return <h1>{count}</h1>;
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question