React Query と GraphQL Code Generator で Mutation
React Query を単体で使わずいきなり GraphQL Code Generator と組み合わせたために Mutation の実行方法がわからず手こずったので結論を書く。
開発環境
- react: 18.0.0
- graphql: 15.8.0
- @graphql-codegen/typescript: 2.4.11
- @graphql-codegen/typescript-operations: 2.4.0
- @graphql-codegen/typescript-react-query: 3.5.12
- react-query: 3.39.1
- typescript: 4.6.3
- vite: 2.9.7
本文
前提として既に『React Query と GraphQL Code Generator 初期設定』の内容は終わっているものとする。
またスキーマは以下とする。
クエリの定義
今回の例として ./src/api/query.graphql に下記のクエリを記述する。
mutation updateBlog($input: UpdateBlogInput!) {
updateBlog(input: $input) {
id
blogKey
author
name
description
publishOption
createdAt
updatedAt
links {
id
name
url
}
}
}
プロジェクトルート(codegen.yaml と同じ階層)で
npm run generate
のコマンドを実行すると、./src/api/generated.ts にコードが生成される。
生成内容を抜粋する。
export type UpdateBlogMutationVariables = Exact<{
input: UpdateBlogInput;
}>;
export type UpdateBlogMutation = { __typename?: 'Mutation', updateBlog?: { __typename?: 'Blog', id: string, blogKey: string, author: string, name: string, description: string, publishOption: PublishOption, createdAt: string, updatedAt: string, links?: Array<{ __typename?: 'BlogLink', id: string, name: string, url: string } | null> | null } | null };
export const UpdateBlogDocument = `
mutation updateBlog($input: UpdateBlogInput!) {
updateBlog(input: $input) {
id
blogKey
author
name
description
publishOption
createdAt
updatedAt
links {
id
name
url
}
}
}
`;
export const useUpdateBlogMutation = <
TError = any,
TContext = unknown
>(options?: UseMutationOptions<UpdateBlogMutation, TError, UpdateBlogMutationVariables, TContext>) =>
useMutation<UpdateBlogMutation, TError, UpdateBlogMutationVariables, TContext>(
['updateBlog'],
(variables?: UpdateBlogMutationVariables) => fetcher<UpdateBlogMutation, UpdateBlogMutationVariables>(UpdateBlogDocument, variables)(),
options
);
生成された hook の使用
最小のコードを抜粋すると、以下のようにすると動く。
import {
UpdateBlogInput,
UpdateBlogMutationVariables,
useUpdateBlogMutation,
// 中略
} from "../../api/generated";
// 中略
export function Index() {
// 中略
const { mutateAsync } = useUpdateBlogMutation({
onError: (e: any) => {
console.error(e);
},
onSuccess: () => {
console.log('success');
},
});
const mutate = async (variables: UpdateBlogMutationVariables) =>
await mutateAsync({
input: variables.input,
});
const onSubmit = (data: any) => {
const input: UpdateBlogInput = {
id: blogId,
author: data.author
};
mutate({ input });
};
return (
<div>
// 中略
</div>
);
}
ポイントとしては useUpdateBlogMutation
はあくまでも hook なのでトップレベルでしか呼べない。
トップレベルに書いた時点ではまだ Mutation は動かず mutateAsync
というのが取れる。
mutateAsync
を呼ぶことによって Mutation を実行できる。
mutateAsync
以外にも色々使えるので公式ドキュメント参照。
以上