Ответы пользователя по тегу React
  • Почему при изменении состояния react-компонента в setInterval, значение состояния каждый раз сбрасывается к исходному?

    MiiZZo
    @MiiZZo Автор вопроса
    JavaScript, React, NodeJS, Student
    Пояснение из документации React:
    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>;
    }

    Пустой набор зависимостей [] означает, что эффект будет выполняться только один раз, когда компонент монтируется, а не при каждом повторном рендере. Проблема в том, что внутри обратного вызова setInterval значение count не изменяется, потому что мы создали замыкание со значением count, установленным в 0, как это было при выполнении обратного вызова эффекта. Каждую секунду этот обратный вызов вызывает setCount(0 + 1), поэтому счетчик никогда не превышает 1.

    Если переписать список зависимостей как [count], то баг будет устранён, но это приведёт к сбрасыванию интервала при каждом изменении. Такое поведение может быть нежелательно. Чтобы исправить это, мы можем применить форму функционального обновления хука setState, которая позволяет указать, как должно меняться состояние, не ссылаясь явно на текущее состояние:

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