はじめに
React(Next.js/GraphQL)からHasuraを使ったCRUD操作を何回かに分けて見ていきます。
今回は、CRUDのC(Create)について見ていきます。
最終的なゴール
以下のような構成のアプリを作ることです。
目的
- 仕事で使っている技術のキャッチアップと復習
- 使う可能性がある技術の理解度向上
ベースとなる記事のリンク
この記事は以下の記事がベースとなっております。
全体のコードなどはそちらに記載があります。
詳細👇
Createに関するカスタムフック
使う関数はuseMutationです。というか、R以外は、useMutationと思っても良いかも。
const [insert_users_one] = useMutation<CreateUserMutation>(CREATE_USER, {
update(cache, { data: { insert_users_one } }) {
const cacheId = cache.identify(insert_users_one)
cache.modify({
fields: {
users(existingUsers, { toReference }) {
return [toReference(cacheId), ...existingUsers]
},
},
})
},
})
ジェネリクスの型は./types/generated/graphqlから来たCreateUserMutationですね。
型定義はこんな感じ。
export type CreateUserMutation = {
__typename?: 'mutation_root'
insert_users_one?:
| { __typename?: 'users'; id: any; name: string; created_at: any }
| null
| undefined
}
キャッシュ更新部分
Updateの場合は、Apolloがキャッシュ内の各オブジェクトの __typename と id を見て、レスポンスの内容と一致するものを自動で更新してくれます。
ですが、CreateとDeleteの場合は、処理が終わったとに、キャッシュが自動的に更新されない仕様になっています。
なので、Createの処理が終わった後、updateという関数を使っていきます。
updateオプションの引数で現状のキャッシュとレスポンスのオブジェクトが受け取れるので、これを利用してキャッシュを更新します。
戻り値を元に一覧のキャッシュを更新できます。
詳細は👇
クローズアップするとこんな感じ
update(cache, { data: { insert_users_one } }) {
const cacheId = cache.identify(insert_users_one)
cache.modify({
fields: {
users(existingUsers, { toReference }) {
return [toReference(cacheId), ...existingUsers]
},
},
})
}
仮にコレをAとすると、以下のようなコードになりますね。
const [insert_users_one] = useMutation<CreateUserMutation>(CREATE_USER, A)
関数useMutationの第二引数ということがわかります。
CREATE_USERの中身を見ると、
export const CREATE_USER = gql`
mutation CreateUser($name: String!) {
insert_users_one(object: { name: $name }) {
id
name
created_at
}
}
`
戻り値が以下であるとわかります。
id
name
created_at
帰ってくる時のフィールド名がinsert_users_oneという名前で1つのユーザー情報が返ってきます。
それをこちら👇で受け取っていることがわります。
次に、以下で、キャッシュのIDを取得することができます。
cache.identify()
つまり、作成したuserのキャッシュのidを取得します。
以前、どこかの記事で説明したかもしれませんが、キャッシュは__typenameとidを組み合わせて作成します。
その組み合わせをキャッシュのkeyとして変数cacheIdに格納されます。
例 users:7c7fdd99-4e42-4fc5-b24d-b9fa49ee2345
こんな感じのデータが格納されます。
続いて、toReferenceの引数に変数cacheIdを渡すと、idをkeyとして、作成したユーザー情報が展開されます。
cache.modify({
fields: {},
})
fields部分は、更新したいfieldを指定できます。指定したら。そのフィールドが更新されます。
今回は、usersフィールドを書き換えるので、usersを指定しています。
usersの第一引数には既存のキャッシュの配列を取得できます。それをexistingUsersという名前で受け取ります。
キャッシュの更新自体はここの処理です。
return [toReference(cacheId), ...existingUsers]
配列の中にある
-
existingUsersをスプレッドで展開してる -
toReference(cacheId)これで、作成したユーザー情報を展開している
これで、配列の先頭に新規作成したユーザーが足されてruturnされているとわかります。
これが、キャッシュに新規作成ユーザーを追加するまでの過程です。
新規ユーザーを作成
試しに、新規ユーザーを作成します。
Hasuraからも追加できたことがわかります。
これから、キャッシュの検索key()はusers:7c7fdd99-4e42-4fc5-b24d-b9fa49ee2345であるとわかりますね。
Networkみると、以下のようなJsonデータが、GraphQlに送られていたことがわかります。
{
"operationName":"CreateUser",
"variables":{
"name":"aaa"
},
"query":"mutation CreateUser($name: String!) {\n insert_users_one(object: {name: $name}) {\n id\n name\n created_at\n __typename\n }\n}\n"
}
CRUDのCの流れはこんな感じです。
今日のところは以上です。
次回以降で、他の処理も見てきます。ありがとうございました。
参考
アウトプット100本ノック実施中



