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

Что в React Query облегчает разработку и создание запросов на сервер?

2.2 Middle🔥 221 комментариев
#React#Архитектура и паттерны

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

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

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

React Query: облегчение разработки и работа с сервером

React Query (теперь TanStack Query) — это одна из самых мощных библиотек для управления server state в React приложениях. Она действительно облегчает разработку на порядки, убирая много boilerplate кода и решая множество проблем, с которыми обычно сталкиваются разработчики при работе с API.

Главные преимущества React Query

1. Автоматическое кэширование и синхронизация Bез React Query нужно вручную управлять состоянием, переписывать статус загрузки, ошибки. React Query всё делает автоматически:

// БЕЗ React Query - куча boilerplate
function useUserData(userId) {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => {
        setData(data);
        setIsLoading(false);
      })
      .catch(err => {
        setError(err);
        setIsLoading(false);
      });
  }, [userId]);
  
  return { data, isLoading, error };
}

// С React Query - одна строка
function useUserData(userId) {
  return useQuery({
    queryKey: ["users", userId],
    queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),
  });
}

Так как React Query кэширует результаты по queryKey, если мы снова запросим того же пользователя — данные вернутся мгновенно из кэша, без нового запроса на сервер.

2. Стейл-вайл-ривалидейт (Stale-While-Revalidate) Этот паттерн позволяет показывать закэшированные данные, пока в фоне идёт обновление:

const { data, isLoading, isFetching } = useQuery({
  queryKey: ["posts"],
  queryFn: fetchPosts,
  staleTime: 1000 * 60 * 5, // 5 минут свежих данных
  gcTime: 1000 * 60 * 10,    // Удалить из кэша через 10 минут
});

// Если данные старше 5 минут, они в фоне обновляются
// Но пользователь видит старые данные до этого
return (
  <div>
    {data && <PostList posts={data} />}
    {isFetching && <small>Обновляется...</small>}
  </div>
);

3. Автоматическая инвалидация и переделение После создания или обновления данных нужно автоматически обновить кэш:

function CreatePostForm() {
  const queryClient = useQueryClient();
  
  const mutation = useMutation({
    mutationFn: (newPost) => 
      fetch("/api/posts", {
        method: "POST",
        body: JSON.stringify(newPost),
      }).then(r => r.json()),
    
    onSuccess: () => {
      // После успешного создания инвалидируем кэш списка постов
      queryClient.invalidateQueries({ queryKey: ["posts"] });
    },
  });
  
  return (
    <form onSubmit={(e) => {
      e.preventDefault();
      mutation.mutate({ title: "Новый пост" });
    }}>
      <button type="submit" disabled={mutation.isPending}>
        {mutation.isPending ? "Создание..." : "Создать"}
      </button>
      {mutation.isError && <p>Ошибка: {mutation.error.message}</p>}
    </form>
  );
}

4. Автоматическая переделение при восстановлении сети Если интернет был отключен, React Query автоматически переделает запросы при восстановлении:

const QueryClientConfig = {
  refetchOnWindowFocus: true,
  refetchOnReconnect: true,
  retryOnMount: true,
};

const queryClient = new QueryClient({
  defaultOptions: {
    queries: QueryClientConfig,
  },
});

5. Обработка ошибок и retry логика Автоматические повторы при сетевых ошибках с экспоненциальным backoff:

const { data, error, isError } = useQuery({
  queryKey: ["unreliableAPI"],
  queryFn: fetchUnreliableData,
  retry: 3,              // Повторить 3 раза
  retryDelay: attemptIndex => 
    Math.min(1000 * 2 ** attemptIndex, 30000), // Экспоненциальный backoff
});

6. Фоновая переделение Автоматическое обновление данных в фоне при определённых условиях:

const { data } = useQuery({
  queryKey: ["notifications"],
  queryFn: fetchNotifications,
  refetchInterval: 5000, // Переделять каждые 5 секунд
  refetchIntervalInBackground: true, // Даже когда таб неактивен
});

7. Кэширование оптимистичных обновлений Сразу показываем изменение пользователю, но если ошибка — откатываем:

const queryClient = useQueryClient();
const { mutate } = useMutation({
  mutationFn: updatePost,
  onMutate: async (updatedPost) => {
    // Отменяем текущие запросы
    await queryClient.cancelQueries({ queryKey: ["posts"] });
    
    // Сохраняем старые данные
    const previousPosts = queryClient.getQueryData(["posts"]);
    
    // Оптимистично обновляем
    queryClient.setQueryData(["posts"], (old) => 
      old.map(p => p.id === updatedPost.id ? updatedPost : p)
    );
    
    return { previousPosts };
  },
  onError: (err, newPost, context) => {
    // Откатываем при ошибке
    queryClient.setQueryData(["posts"], context.previousPosts);
  },
});

8. Бесконечные списки и пагинация Легко реализовать infinite scroll или load more:

function InfinitePostList() {
  const {
    data,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery({
    queryKey: ["posts"],
    queryFn: ({ pageParam }) => 
      fetch(`/api/posts?page=${pageParam}`).then(r => r.json()),
    initialPageParam: 1,
    getNextPageParam: (lastPage, pages) => 
      lastPage.hasMore ? pages.length + 1 : undefined,
  });
  
  return (
    <div>
      {data?.pages.map(page => 
        page.posts.map(post => <Post key={post.id} post={post} />)
      )}
      <button 
        onClick={() => fetchNextPage()}
        disabled={!hasNextPage || isFetchingNextPage}
      >
        {isFetchingNextPage ? "Загружаю..." : "Загрузить ещё"}
      </button>
    </div>
  );
}

Практические примеры из реальных проектов

Глобальное управление фильтрами с React Query:

function useFilteredPosts(filters) {
  const queryClient = useQueryClient();
  
  const { data, isLoading } = useQuery({
    queryKey: ["posts", filters],
    queryFn: () => fetchPosts(filters),
  });
  
  const updateFilter = useCallback((newFilters) => {
    // Инвалидируем старые данные
    queryClient.setQueryData(
      ["posts", filters],
      undefined
    );
  }, [queryClient, filters]);
  
  return { data, isLoading, updateFilter };
}

Почему это облегчает разработку

  1. Меньше кода — не нужно писать useEffect, обработку ошибок, состояния
  2. Лучший UX — автоматическое кэширование, переделение, обработка оффлайн сценариев
  3. Производительность — умное кэширование снижает нагрузку на сервер
  4. DevTools — отличные DevTools для отладки состояния запросов
  5. Надёжность — обработка граничных случаев (retry, timeout, cancellation)

React Query экономит часы разработки и делает код значительно более качественным и надёжным.

Что в React Query облегчает разработку и создание запросов на сервер? | PrepBro