はじめに
小さなLTに挑戦してみたので、その時に調べた事をまとめました
LTの内容を Apolloのキャッシュとリストの更新の記事と2つに分割しています。
使用技術
- React
- Apollo Client
- GraphQL Code Generator
- Hasura(GraphQLサーバー側。今回はそこまで関係ないかも)
サンプルアプリ
画面イメージ
DB
usersテーブル:id, name
todosテーブル:id, user_id, title, created_at, updated_at
userがtodoのリストを持っている
ソースコード
https://github.com/tokio-k/LT-sample-apollo-fragment-and-modify-cache
(Apolloのキャッシュとリストの更新の記事の内容も入っています)
書き方
TodoFragmentを作る場合
.ts
gql`
fragment Todo on todos {
id
title
created_at
updated_at
}
`
用途
再利用できるため、書く量が減る&変更に強くなる
Fragmentなし
.ts
gql`
query GetUser($id: Int!) {
users_by_pk(id: $id) {
id
name
todos {
id
title
created_at
updated_at
}
}
}
`;
gql`
mutation AddTodo($user_id: Int!, $title: String!) {
insert_todos_one(object: { title: $title, user_id: $user_id }) {
id
title
created_at
updated_at
}
}
mutation UpdateTodo($id: Int!, $title: String!) {
update_todos_by_pk(pk_columns: { id: $id }, _set: { title: $title }) {
id
title
created_at
updated_at
}
}
`;
Fragmentあり
.ts
gql`
query GetUser($id: Int!) {
users_by_pk(id: $id) {
id
name
todos {
...Todo
}
}
}
`;
gql`
mutation AddTodo($user_id: Int!, $title: String!) {
insert_todos_one(object: { title: $title, user_id: $user_id }) {
...Todo
}
}
mutation UpdateTodo($id: Int!, $title: String!) {
update_todos_by_pk(pk_columns: { id: $id }, _set: { title: $title }) {
...Todo
}
}
`;
gql`
fragment Todo on todos {
id
title
created_at
updated_at
}
`;
一つの変更で済みますね
簡単に型の定義ができる
propsの型に使う
.ts
{data?.users_by_pk?.todos.map((todo) => { // users_by_pk・・① todo・・②
return (
<li key={todo.id}>
<Todo todo={todo} />
</li>
);
})}
graphql.ts
// ①のusers_by_pkの型(自動生成された)
Maybe<(
{ __typename?: 'users' }
& Pick<Users, 'id' | 'name'>
& { todos: Array<(
{ __typename?: 'todos' }
& Pick<Todos, 'id' | 'title' | 'created_at' | 'updated_at'>
)> }
)>
// ②のtodoの型(自動生成された)
{ __typename?: 'todos' }
& Pick<Todos, 'id' | 'title' | 'created_at' | 'updated_at'>
// TodoFragmentで生成された型(自動生成された)
export type TodoFragment = (
{ __typename?: 'todos' }
& Pick<Todos, 'id' | 'title' | 'created_at' | 'updated_at'>
);
②のtodoの型とTodoFragmentで生成された型は同じ
.ts
type TodoType = { todo: TodoFragment };
const Todo: VFC<TodoType> = ({ todo }) => {
...
...
}
キャッシュの書き換えで使用
user1がTodoを追加するMutationの後
user1のTodoリストを更新する場合のイメージ
.ts
const [addTodo] = useAddTodoMutation({
update(cache, { data }) {
cache.modify({
id: cache.identify({ id: 1, __typename: "users" }),
fields: {
todos(existing = []) {
const newTodoRef = cache.writeFragment({
data: data?.insert_todos_one,
fragment: TodoFragmentDoc, //←これ
});
return [...existing, newTodoRef];
},
},
});
},
});
(Apolloのキャッシュとリストの更新の記事に詳細を記載)
まとめ
Fragmentの使用方法
- 再利用できるため、書く量が減る&変更に強くなる
- 簡単に型の定義ができる
- キャッシュの書き換えで使用
参考記事