8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ApolloのFragmentの使い方

Last updated at Posted at 2021-09-25

はじめに

小さなLTに挑戦してみたので、その時に調べた事をまとめました
LTの内容を Apolloのキャッシュとリストの更新の記事と2つに分割しています。

使用技術

  • React
  • Apollo Client
  • GraphQL Code Generator
  • Hasura(GraphQLサーバー側。今回はそこまで関係ないかも)

サンプルアプリ

画面イメージ

スクリーンショット 2021-09-24 13.16.11.png

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の使用方法

  1. 再利用できるため、書く量が減る&変更に強くなる
  2. 簡単に型の定義ができる
  3. キャッシュの書き換えで使用

参考記事

8
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?