React Hooks setInterval утечка памяти - PullRequest
1 голос
/ 03 апреля 2020

Я создал компонент таймера обратного отсчета, который передает данные другому компоненту, и я использую setTimeout. Компонент работает должным образом, но в моей консоли появляется предупреждение:

Предупреждение. Невозможно выполнить обновление состояния React для неустановленного компонента. Это неоперация, но она указывает на утечку памяти в вашем приложении. Чтобы исправить, отмените все подписки и асинхронные задачи в функции очистки useEffect.

Поскольку я использую setTimeout в useEffect Я пытался добавить clearInterval в функцию возврата, но это не кажется, чтобы помочь. Ниже вы можете найти мой компонент:

export default function createEvent(WrappedComponent) {
  const Event = props => {
    const [{ endDate }] = useState(props);
    const [days, setDays] = useState('');
    const [hours, setHours] = useState('');
    const [minutes, setMinutes] = useState('');
    const [seconds, setSeconds] = useState('');

    const interval = useRef();

    useEffect(() => {
      interval.current = setInterval(() => {
        const date = moment.unix(endDate).format('MM DD YYYY, h:mm a');
        const then = moment(date, 'MM DD YYYY, h:mm a');
        const now = moment();
        const countdown = moment(then - now);
        const daysFormat = countdown.format('D');
        const hoursFormat = countdown.format('HH');
        const minutesFormat = countdown.format('mm');
        const secondsFormat = countdown.format('ss');

        setDays(`${daysFormat} days`);
        setHours(hoursFormat);
        setMinutes(minutesFormat);
        setSeconds(secondsFormat);

        return () => {
          clearInterval(interval.current);
          interval.current = null;
        };
      }, 1000);
    }, []);

    return (
      <WrappedComponent
        days={days}
        hours={hours}
        minutes={minutes}
        seconds={seconds}
        {...props}
      />
    );
  };

  return Event;
}

Если я попытаюсь имитировать очистку из другого места, добавив еще один useEffect прямо под последним, например:

  useEffect(() => {
    setTimeout(() => clearInterval(interval.current), 15000)
  }, [])

Предупреждение исчезнет, ​​но обратный отсчет больше не будет работать. Так как мне сделать это правильно, чтобы не влиять на обратный отсчет и очистить предупреждение?

Ответы [ 3 ]

1 голос
/ 03 апреля 2020

Функция очистки для useEffect hook [1] должна быть возвращена из функции, которую вы задаете для useEffect. Вы возвращаете свою функцию очистки в функции, которую вы даете setInterval.

useEffect(() => {
  interval.current = setInterval(() => {
    const date = moment.unix(endDate).format('MM DD YYYY, h:mm a');
    const then = moment(date, 'MM DD YYYY, h:mm a');
    const now = moment();
    const countdown = moment(then - now);
    const daysFormat = countdown.format('D');
    const hoursFormat = countdown.format('HH');
    const minutesFormat = countdown.format('mm');
    const secondsFormat = countdown.format('ss');

    setDays(`${daysFormat} days`);
    setHours(hoursFormat);
    setMinutes(minutesFormat);
    setSeconds(secondsFormat);
  }, 1000);

  // move clean up function to here:
  return () => {
    clearInterval(interval.current);
    interval.current = null;
  };
}, []);

[1] https://reactjs.org/docs/hooks-effect.html

0 голосов
/ 03 апреля 2020

Вам не нужно createRef для effects. и возвращение должно быть after the interval.

useEffect(() => {
      const timer = setInterval(() => {
        const date = moment.unix(endDate).format('MM DD YYYY, h:mm a');
        const then = moment(date, 'MM DD YYYY, h:mm a');
        const now = moment();
        const countdown = moment(then - now);
        const daysFormat = countdown.format('D');
        const hoursFormat = countdown.format('HH');
        const minutesFormat = countdown.format('mm');
        const secondsFormat = countdown.format('ss');

        setDays(`${daysFormat} days`);
        setHours(hoursFormat);
        setMinutes(minutesFormat);
        setSeconds(secondsFormat);

      }, 1000);

       return () => {
          clearInterval(timer);
        };
    }, []);
0 голосов
/ 03 апреля 2020
useEffect(() => {
      interval.current = setInterval(() => {
        const date = moment.unix(endDate).format('MM DD YYYY, h:mm a');
        const then = moment(date, 'MM DD YYYY, h:mm a');
        const now = moment();
        const countdown = moment(then - now);
        const daysFormat = countdown.format('D');
        const hoursFormat = countdown.format('HH');
        const minutesFormat = countdown.format('mm');
        const secondsFormat = countdown.format('ss');

        setDays(`${daysFormat} days`);
        setHours(hoursFormat);
        setMinutes(minutesFormat);
        setSeconds(secondsFormat);
      }, 1000);

  // Attention : return function cleanup for the function used in useEffect()
  return () => {
      clearInterval(interval.current);
      interval.current = null;
    };
}, []);

Вы можете просмотреть мой полный ответ "Устранение утечек памяти на неустановленном компоненте в зацеплениях" прямо здесь: { ссылка }

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...