Как очистить setInterval в useEffect, используя реакционные хуки - PullRequest
4 голосов
/ 19 апреля 2019

Я пытаюсь создать загрузочный компонент, который будет периодически добавлять период в div, каждые 1000 мс, используя setInterval в React. Я пытаюсь очистить setInterval, используя метод, описанный в документации.

https://reactjs.org/docs/hooks-effect.html#example-using-hooks-1

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

const Loading = () => {
    const [loadingStatus, setLoadingStatus] = useState('.')
    const [loop, setLoop] = useState()
    useEffect(() => {
        setLoop(setInterval(() => {
            console.log("loading")
            setLoadingStatus(loadingStatus + ".")
        }, 1000))

        return function cleanup() {
            console.log('cleaning up')
            clearInterval(loop)
        }
    }, [])
    return (<p>
        {`Loading ${loadingStatus}`}
    </p>)
}
export default Loading

Однако переменная loadingStatus обновляется только один раз, и цикл setInterval не очищается даже после прекращения монтирования компонента. Должен ли я сделать это, используя компонент класса?

1 Ответ

3 голосов
/ 19 апреля 2019

Зависимости - это наша подсказка для React о том, когда должен запускаться эффект, даже если мы установили интервал и не предоставили никаких зависимостей [], React не будет знать, что мы хотим запустить его более одного раза, потому что в наших пустых зависимостях ничего не меняется 1002 *.

Чтобы получить желаемый результат, нам нужно подумать, когда мы хотим запустить эффект?

Мы хотим запустить его при изменении loadingStatus, поэтому нам нужно добавить loadingStatus в качестве нашей зависимости, потому что мы хотим запускать эффект каждый раз, когда loadingStatus изменяется.

У нас есть 2 варианта

Добавьте loadingStatus в качестве нашей зависимости.

const Loading = () => {
  const [loadingStatus, setLoadingStatus] = useState(".");
  const [loop, setLoop] = useState();

  useEffect(
    () => {
      setLoop(
        setInterval(() => {
          console.log("loading");
          setLoadingStatus(loadingStatus + ".");
        }, 1000)
      );

      return function cleanup() {
        console.log("cleaning up");
        clearInterval(loop);
      };
    },
    [loadingStatus]
  );

  return <p>{`Loading ${loadingStatus}`}</p>;
};

Сделайте так, чтобы наш эффект не знал, что мы используем loadingStatus

const Loading = () => {
  const [loadingStatus, setLoadingStatus] = useState(".");

  useEffect(() => {
    const intervalId = setInterval(() => {
      setLoadingStatus(ls => ls + ".");
    }, 1000);

    return () => clearInterval(intervalId);
  }, []);

  return <p>{`Loading ${loadingStatus}`}</p>;
};

Подробнее здесь => полный справочник по использованию

...