Use Cases

TanStack Query con Claude Code

Aprenda sobre TanStack Query usando Claude Code. Incluye consejos practicos y ejemplos de codigo.

TanStack Queryでサーバー状態管理を最適化する

TanStack Query(旧React Query)はサーバー状態の取得・キャッシュ・同期を宣言的に管理するライブラリです。Claude Codeを使えば、複雑なキャッシュ戦略や楽観的更新も素早く実装できます。

基本的なクエリ設計

Claude Codeにデータ取得パターンを依頼しましょう。

> TanStack Queryでユーザー一覧のクエリを作成して。
> ページネーション、検索フィルタ、自動リフレッシュ対応で。
import { useQuery, keepPreviousData } from "@tanstack/react-query";

// クエリキーファクトリー
export const userKeys = {
  all: ["users"] as const,
  lists: () => [...userKeys.all, "list"] as const,
  list: (filters: UserFilters) => [...userKeys.lists(), filters] as const,
  details: () => [...userKeys.all, "detail"] as const,
  detail: (id: string) => [...userKeys.details(), id] as const,
};

interface UserFilters {
  page: number;
  perPage: number;
  search?: string;
  role?: string;
}

export function useUsers(filters: UserFilters) {
  return useQuery({
    queryKey: userKeys.list(filters),
    queryFn: () => fetchUsers(filters),
    placeholderData: keepPreviousData,
    staleTime: 5 * 60 * 1000, // 5分間はキャッシュを使用
    refetchOnWindowFocus: true,
  });
}

export function useUser(id: string) {
  return useQuery({
    queryKey: userKeys.detail(id),
    queryFn: () => fetchUser(id),
    enabled: !!id,
    staleTime: 10 * 60 * 1000,
  });
}

楽観的更新の実装

ミューテーションと楽観的更新のパターンをClaude Codeに生成してもらいます。

import { useMutation, useQueryClient } from "@tanstack/react-query";

export function useUpdateUser() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (data: { id: string; updates: Partial<User> }) =>
      updateUser(data.id, data.updates),

    onMutate: async ({ id, updates }) => {
      // 進行中のクエリをキャンセル
      await queryClient.cancelQueries({ queryKey: userKeys.detail(id) });

      // 現在のデータをバックアップ
      const previousUser = queryClient.getQueryData(userKeys.detail(id));

      // キャッシュを楽観的に更新
      queryClient.setQueryData(userKeys.detail(id), (old: User) => ({
        ...old,
        ...updates,
      }));

      return { previousUser };
    },

    onError: (_err, { id }, context) => {
      // エラー時にロールバック
      if (context?.previousUser) {
        queryClient.setQueryData(userKeys.detail(id), context.previousUser);
      }
    },

    onSettled: (_data, _error, { id }) => {
      // 成功・失敗に関わらず再取得
      queryClient.invalidateQueries({ queryKey: userKeys.detail(id) });
      queryClient.invalidateQueries({ queryKey: userKeys.lists() });
    },
  });
}

無限スクロールの実装

useInfiniteQueryを使った無限スクロールもClaude Codeで素早く実装できます。

import { useInfiniteQuery } from "@tanstack/react-query";

export function useInfiniteUsers(search?: string) {
  return useInfiniteQuery({
    queryKey: ["users", "infinite", { search }],
    queryFn: ({ pageParam }) =>
      fetchUsers({ page: pageParam, perPage: 20, search }),
    initialPageParam: 1,
    getNextPageParam: (lastPage) =>
      lastPage.hasNext ? lastPage.page + 1 : undefined,
    getPreviousPageParam: (firstPage) =>
      firstPage.hasPrev ? firstPage.page - 1 : undefined,
  });
}

function UserInfiniteList() {
  const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
    useInfiniteUsers();

  const users = data?.pages.flatMap((page) => page.users) ?? [];

  return (
    <div>
      {users.map((user) => (
        <UserCard key={user.id} user={user} />
      ))}
      {hasNextPage && (
        <button onClick={() => fetchNextPage()} disabled={isFetchingNextPage}>
          {isFetchingNextPage ? "Loading..." : "もっと見る"}
        </button>
      )}
    </div>
  );
}

プリフェッチとSSR対応

Next.jsなどでのサーバーサイドプリフェッチも実装できます。

import { QueryClient, dehydrate, HydrationBoundary } from "@tanstack/react-query";

export async function getServerSideProps() {
  const queryClient = new QueryClient();

  await queryClient.prefetchQuery({
    queryKey: userKeys.list({ page: 1, perPage: 20 }),
    queryFn: () => fetchUsers({ page: 1, perPage: 20 }),
  });

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  };
}

export default function UsersPage({
  dehydratedState,
}: {
  dehydratedState: unknown;
}) {
  return (
    <HydrationBoundary state={dehydratedState}>
      <UserList />
    </HydrationBoundary>
  );
}

カスタムクエリフックのパターン

実務では再利用可能なカスタムフックとして設計します。

function useOptimisticDelete<T extends { id: string }>(
  queryKey: readonly unknown[],
  deleteFn: (id: string) => Promise<void>
) {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: deleteFn,
    onMutate: async (id) => {
      await queryClient.cancelQueries({ queryKey });
      const previous = queryClient.getQueryData(queryKey);

      queryClient.setQueryData(queryKey, (old: T[] | undefined) =>
        old?.filter((item) => item.id !== id)
      );

      return { previous };
    },
    onError: (_err, _id, context) => {
      queryClient.setQueryData(queryKey, context?.previous);
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey });
    },
  });
}

Summary

TanStack Queryはサーバー状態管理の複雑さを大幅に軽減してくれます。Claude Codeを活用すれば、クエリキー設計、楽観的更新、無限スクロールなどの複雑なパターンも短時間で実装可能です。

状態管理の全体設計はZustand状態管理ガイドを、APIの型安全性はtRPC型安全API開発を参照してください。TanStack Query公式ドキュメントも確認しておきましょう。

#Claude Code #TanStack Query #React #データ取得 #caching