← Назад к вопросам

Что такое Recancellation в React?

2.0 Middle🔥 131 комментариев
#React

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Recancellation в React?

Recancellation — важный паттерн в React для управления асинхронными операциями и предотвращения утечек памяти. Это механизм для отмены или переквалификации выполняющихся операций при изменении зависимостей.

Основная проблема

Когда компонент размонтируется или зависимости useEffect изменяются, старые асинхронные операции могут всё ещё выполняться. Это вызывает ошибку: "Warning: Can't perform a React state update on an unmounted component."

Решение 1: AbortController

Стандартный способ отмены запросов:

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    const controller = new AbortController();
    const signal = controller.signal;
    
    fetch(`/api/users/${userId}`, { signal })
      .then(res => res.json())
      .then(data => {
        if (!signal.aborted) {
          setUser(data);
        }
      });
    
    return () => controller.abort();
  }, [userId]);
  
  return <div>{user?.name}</div>;
}

Решение 2: Флаг isMounted

Традиционный подход:

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    let isMounted = true;
    
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => {
        if (isMounted) setUser(data);
      });
    
    return () => { isMounted = false; };
  }, [userId]);
  
  return <div>{user?.name}</div>;
}

Решение 3: Пользовательский хук useFetch

Переиспользуемое решение:

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    const controller = new AbortController();
    let isMounted = true;
    
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch(url, { signal: controller.signal });
        const result = await response.json();
        
        if (isMounted) setData(result);
      } catch (err) {
        if (isMounted && err.name !== 'AbortError') {
          setError(err);
        }
      } finally {
        if (isMounted) setLoading(false);
      }
    };
    
    fetchData();
    
    return () => {
      isMounted = false;
      controller.abort();
    };
  }, [url]);
  
  return { data, loading, error };
}

Решение 4: Управление несколькими запросами

function ComplexDataFetcher({ ids }) {
  const [results, setResults] = useState({});
  
  useEffect(() => {
    const controllers = new Map();
    
    const fetchAll = async () => {
      for (const id of ids) {
        const ctrl = new AbortController();
        controllers.set(id, ctrl);
        
        try {
          const response = await fetch(`/api/data/${id}`, {
            signal: ctrl.signal
          });
          const data = await response.json();
          setResults(prev => ({ ...prev, [id]: data }));
        } catch (err) {
          if (err.name !== 'AbortError') console.error(err);
        }
      }
    };
    
    fetchAll();
    
    return () => {
      controllers.forEach(ctrl => ctrl.abort());
    };
  }, [ids]);
  
  return <div></div>;
}

Практические советы

Всегда используй AbortController для стандартизированной отмены запросов. Библиотеки, которые справляются с Recancellation: TanStack Query, SWR, axios.

Итоги

Recancellation в React:

  1. Проблема: асинхронные операции продолжают выполняться после размонтирования
  2. Решение: отмена запросов через cleanup функцию useEffect
  3. Лучший способ: AbortController для современной отмены
  4. Альтернатива: флаги isMounted для проверки перед setState
  5. Библиотеки: автоматический Recancellation в query clients

Это критично для предотвращения утечек памяти и Warning'ов в консоли.

Что такое Recancellation в React? | PrepBro