Не удается выполнить обновление состояния реакции для «размонтированного` компонента

#reactjs

#reactjs

Вопрос:

это серьезная проблема?

при попытке перейти на другую страницу через react-router я вижу следующую ошибку <link>

 warning: Can't perform a React state update on an unmounted component.
 This is a no-op, but it indicates a memory leak in your application.
To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
            at Timer
 

вот эффект использования таймера

  useEffect(() => {
    const current = interval.current;
    startTimer()
    return () => {
      clearInterval(current)
    }
  })
 

вот интервал, он принимает дату, затем вычисляет разницу, а затем возвращает ее в useState hook

   let interval = useRef();
  const startTimer = () => {
    const countdownDate = new Date(`${data.remainTimeRanking}`).getTime()
    interval = setInterval(() => {
      const now = new Date().getTime()
      const distance = countdownDate - now;
      const days = Math.floor(distance / (1000 * 60 * 60 * 24));
      const hours = Math.floor((distance % (1000 * 60 * 60 * 24) / (1000 * 60 * 60)))
      const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
      const seconds = Math.floor((distance % (1000 * 60)) / 1000)
      if (distance < 0) {
        clearInterval(interval.current)
      } else {
        setTimerDays(days)
        setTimerHours(hours)
        setTimerMinutes(minutes);
        setTimerSeconds(seconds)
      }
    }, 1000);
  };  
 

Комментарии:

1. было бы полезно, чтобы люди оказывали вам лучшую помощь, если вы показываете, как вы устанавливаете interval , и какое значение вы передаете interval.current

2. Я добавил интервал 🙂

Ответ №1:

вы не должны перезаписывать свою переменную ref другим значением. после создания экземпляра переменной ref то, что вы хотите привязать, должно быть сохранено в current attribute .

Следовательно, вам необходимо связать setInterval возвращаемое значение с current атрибутом из interval :

 interval.current = setInterval(() => {
  const now = new Date().getTime()
  const distance = countdownDate - now;
  const days = Math.floor(distance / (1000 * 60 * 60 * 24));
  const hours = Math.floor((distance % (1000 * 60 * 60 * 24) / (1000 * 60 * 60)))
  const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
  const seconds = Math.floor((distance % (1000 * 60)) / 1000)
  if (distance < 0) {
    clearInterval(interval.current)
  } else {
    setTimerDays(days)
    setTimerHours(hours)
    setTimerMinutes(minutes);
    setTimerSeconds(seconds)
  }
}, 1000);
 

при useEffect также просто передайте interval.current напрямую и передайте [] в качестве второго аргумента для выполнения вашего useEffect only on mount:

  useEffect(() => {
    startTimer()
    return () => {
      clearInterval(interval.current)
    }
  }, [])