🧊
Tanstack Query 〜 Reusable な useQuery を目指して 〜
非同期処理の状態管理としてTanstack Queryを導入した際の活用方法についてです。
ポイントはこちら
-
useQuery
をラップしたhooksをAPIエンドポイント毎に定義 -
useQuery
のオプション(例:select
,staleTime
など)を外部から指定可能にする
以下は、useQuery
をラップしてtodos
エンドポイント専用のカスタムフックを作成する例です。
useQuery のオプション型からqueryKey
とqueryFn
を除外し、それ以外のオプションを呼び出し元で自由に指定できるようにしています。
/services/todo.query.ts
import { api } from "@/lib/http-client";
import { type UseQueryOptions, useQuery } from "@tanstack/react-query";
// api res
type TodoDto = {
id: string;
title: string;
};
export const fetcher = async (): Promise<TodoDto[]> => {
const res = await api.get("/todos");
return res.data;
};
export const useTodoQuery = <QueryResult>(
config?: Omit<
UseQueryOptions<TodoDto[], unknown, QueryResult>,
"queryKey" | "queryFn"
>
) => {
return useQuery({
queryKey: ["todos"],
queryFn: fetcher,
...config,
});
};
呼び出す側の実装はこのようになります。
実装例ではAPIレスポンスの整形処理をオプションとして指定しています。
ViewからはuseTodo
hooksを呼び出します。
/usecase/get-todo.ts
import { fetcher, useTodoQuery } from "../service/todo.query";
type TodoDto = Awaited<ReturnType<typeof fetcher>>;
const composeTodo = (res: TodoDto) => {
return res.map((todo) => ({ id: todo.id, title: todo.title }));
};
export const useTodo = () => {
return useTodoQuery({
select: composeTodo,
gcTime: 0,
});
};
例えば、複数のコンポーネントが同じAPIエンドポイントにリクエストする場合、それぞれのコンポーネントに必要なデータの抽出を柔軟にカスタマイズすることも可能ですね。
これにより、APIエンドポイントごとに統一したデータ取得ロジックを持ちながら、必要に応じて柔軟にオプションを指定できます。
Discussion