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

Есть ли что-то встроенное в useFetch чтобы он не вызывался сразу?

2.0 Middle🔥 171 комментариев
#Браузер и сетевые технологии

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Отложенный вызов в useFetch хуке

Вопрос о том, есть ли встроенные механизмы в useFetch для отложения выполнения запроса. Это важная тема, потому что не всегда нужно загружать данные сразу при монтировании компонента.

Проблема

В React хуки с побочными эффектами обычно выполняются при монтировании:

// Это выполняется сразу при монтировании
const { data, loading } = useFetch('/api/users');

Но иногда нам нужно выполнить запрос только по требованию:

  • При клике пользователя на кнопку
  • При ввода в поле поиска
  • При заполнении формы
  • При переходе на определённую вкладку

Стандартные подходы

Подход 1: Параметр enabled (React Query, SWR)

Если вы используете react-query или swr, они имеют встроенный механизм:

import { useQuery } from '@tanstack/react-query';

const { data, isLoading } = useQuery({
  queryKey: ['users', userId],
  queryFn: async () => {
    const response = await fetch(`/api/users/${userId}`);
    return response.json();
  },
  enabled: !!userId // Запрос выполнится только если userId существует
});

Подход 2: Кастомный useFetch с enabled флагом

Если вы пишете свой хук, добавьте параметр:

interface UseFetchOptions {
  enabled?: boolean;
}

function useFetch<T>(url: string, options: UseFetchOptions = {}) {
  const { enabled = true } = options;
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    if (!enabled) return; // Не выполняй если disabled

    const fetchData = async () => {
      setLoading(true);
      try {
        const response = await fetch(url);
        const json = await response.json();
        setData(json);
      } catch (err) {
        setError(err as Error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url, enabled]);

  return { data, loading, error };
}

// Использование
const [userId, setUserId] = useState<string | null>(null);
const { data: user } = useFetch(`/api/users/${userId}`, {
  enabled: !!userId // Загружать только если userId установлен
});

Подход 3: Возвращение функции для ручного вызова

Это более гибкий подход для полного контроля:

function useFetchManual<T>(url: string) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  const fetch = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const response = await fetch(url);
      if (!response.ok) throw new Error('Network error');
      const json = await response.json();
      setData(json);
    } catch (err) {
      setError(err as Error);
    } finally {
      setLoading(false);
    }
  }, [url]);

  return { data, loading, error, fetch }; // Возвращаем функцию!
}

// Использование
const SearchUsers = () => {
  const { data: results, loading, fetch } = useFetchManual('/api/search');

  const handleSearch = async (query: string) => {
    // Запрос выполнится только при клике
    await fetch(`/api/search?q=${query}`);
  };

  return (
    <div>
      <input onChange={(e) => handleSearch(e.target.value)} />
      {loading && <p>Searching...</p>}
      {results && <Results items={results} />}
    </div>
  );
};

Практический пример: Форма с отложенной загрузкой

interface User {
  id: string;
  name: string;
  email: string;
}

function UserForm() {
  const [userId, setUserId] = useState<string | null>(null);
  const { data: user, loading } = useFetch(
    userId ? `/api/users/${userId}` : null,
    { enabled: !!userId }
  );

  return (
    <div className="space-y-4">
      <select onChange={(e) => setUserId(e.target.value || null)}>
        <option value="">Select a user</option>
        <option value="1">User 1</option>
        <option value="2">User 2</option>
      </select>

      {loading && <p>Loading...</p>}
      {user && (
        <div className="p-4 bg-surface-secondary rounded">
          <h3>{user.name}</h3>
          <p>{user.email}</p>
        </div>
      )}
    </div>
  );
}

Сравнение подходов

enabled флаг:

  • Плюсы: просто, встроено в react-query
  • Минусы: всё ещё нужен условный URL или обработка null

Ручная функция fetch:

  • Плюсы: полный контроль, можно вызвать где угодно
  • Минусы: больше кода, нужно самому управлять ошибками

Условный useEffect:

  • Плюсы: понятен логика
  • Минусы: нужно писать сам useEffect

Рекомендация

Для современного стека рекомендую:

  • React Query / TanStack Query — лучший вариант для сложных запросов
  • SWR — если нужно что-то более лёгкое
  • Собственный хук — если хочешь обучиться или управлять параметрами

Вывод

Встроенных механизмов в базовом useFetch нет, но есть несколько проверенных способов:

  1. enabled флаг (React Query / SWR)
  2. Функция fetch (ручной вызов)
  3. Условный useEffect (собственная реализация)

Выбор зависит от требований вашего приложения и предпочтений команды.