Задать вопрос
@1programmer

Как правильно отправить асинхронный запрос в useEffect?

Имеется компонент, модальное окно. При клике, за пределы модального окна, оно закрывается, при открытии - летит асинхронный запрос.
function handleClickOutside(e: MouseEvent) {
    if (wrapModal.current) {
      if (e.target && !wrapModal.current.contains(e.target as Node)) {
        setIsOpen(false);
        setCurrentImg(0);
        setImg(null);
      }
    }
  }

  useEffect(() => {
    const fetchData = async () => {
      await axios.get(url).then((data: any) => {
        setImg(data);
        setPreloader(!preloader);
      });
    };
    fetchData();
  }, [url]);

  useEffect(() => {
    document.addEventListener("mousedown", handleClickOutside, false);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside, false);
    };
  }, []);


Сейчас при клике за пределы модального окна, получаю ошибку:
index.js:1 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.

Как ее исправить ?
  • Вопрос задан
  • 3603 просмотра
Подписаться 2 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 2
@twolegs
В вашем случае нужно избежать апдейта стейта если компонент был размонтирован. Самое верное, на мой взгляд, решение - это отмена запроса при размонтировании. Пример с fetch, т.к. не знаю, есть ли возможность отменить запрос в axios.
useEffect(() => {
    const abortController = new AbortController();
    const fetchData = async () => {
      await fetch(url, { abortController }).then((data: any) => {
        setImg(data);
        setPreloader(!preloader);
      });
    };
    fetchData();

    return () => {
      abortController.abort(); 
    }
  }, [url]);


Если рассмотреть пример выше, теоретически должно сработать такое:
useEffect(() => {
  let isMounted = true; 
  const fetchData = async () => {
   ...
    if (isMounted) {
      setImg(data);
      setPreloader(!preloader);
    }
   ...
  }
  ...
  return () => { isMounted = false; };
}, [])
Ответ написан
Комментировать
pterodaktil
@pterodaktil
js developer
код, который позволяет проверить, вмонтирован ли компонент в DOM, перед тем, как делать setState
const isMounted = useIsMounted();

useEffect(() => {
...
  if (isMounted()) {
    setImg(data);
    setPreloader(!preloader);
  }
...
}, [])

позволяет предотвратить ошибку, когда компонент умер, а запрос еще не отработал
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы