GraphQL codegen

クエリの作成

import { gql } from '@apollo/client'

export const GET_USERS = gql`
  query GetUsers {
    users(order_by: { created_at: desc }) {
      id
      name
      created_at
    }
  }
`
export const GET_USERS_LOCAL = gql`
  query GetUsers {
    users(order_by: { created_at: desc }) @client {
      id
      name
      created_at
    }
  }
`
export const GET_USERIDS = gql`
  query GetUserIds {
    users(order_by: { created_at: desc }) {
      id
    }
  }
`
export const GET_USERBY_ID = gql`
  query GetUserById($id: uuid!) {
    users_by_pk(id: $id) {
      id
      name
      created_at
    }
  }
`
export const CREATE_USER = gql`
  mutation CreateUser($name: String!) {
    insert_users_one(object: { name: $name }) {
      id
      name
      created_at
    }
  }
`
export const DELETE_USER = gql`
  mutation DeleteUser($id: uuid!) {
    delete_users_by_pk(id: $id) {
      id
      name
      created_at
    }
  }
`
export const UPDATE_USER = gql`
  mutation UpdateUser($id: uuid!, $name: String!) {
    update_users_by_pk(pk_columns: { id: $id }, _set: { name: $name }) {
      id
      name
      created_at
    }
  }
`

@clientでGraphQLサーバーではなく、クライアントのキャッシュから取得できる

export const GET_USERS_LOCAL = gql`
  query GetUsers {
    users(order_by: { created_at: desc }) @client {
      id
      name
      created_at
    }
  }
`

$id 引数でidを渡してデータを取得する

export const GET_USERBY_ID = gql`
  query GetUserById($id: uuid!) {
    users_by_pk(id: $id) {
      id
      name
      created_at
    }
  }
`

CreateUser($name: String!)
$name: クエリの引数を変数化
String: 変数の型定義
!: 必須

export const CREATE_USER = gql`
  mutation CreateUser($name: String!) {
    insert_users_one(object: { name: $name }) {
      id
      name
      created_at
    }
  }
`

型の自動生成

yarn gen-types

キャッシュを使ってグローバルなステートの管理を実現。

Queryを発行し、GraphQLサーバからデータを取得
Apollo Clientは取得したデータを自動的にキャッシュに保存する
そのためクライアントサイドでは他のコンポーネントから
同じクエリで@clientをつけるだけで保存されているキャッシュへアクセスできる

ローカルのステートマネジメント
makeVar(userReacticeVar)を標準で提供している

const createApolloClient = () => {
  return new ApolloClient({
    // window === 'undefined' ブラウザではない = サーバーサイドで処理が走る場合
    ssrMode: typeof window === 'undefined',
    link: new HttpLink({
      uri: '',
    }),

    cache: new InMemoryCache(),
  })
}

export const initializeApollo = (initialState = null) => {
  const _apolloClient = apolloClient ?? createApolloClient()
  // For SSG and SSR always create a new Apollo Client
  if (typeof window === 'undefined') return _apolloClient
  // Create the Apollo Client once in the client
  if (!apolloClient) apolloClient = _apolloClient

  return _apolloClient
}
import { ApolloProvider } from '@apollo/client'
import { AppProps } from 'next/app'
import { initializeApollo } from '../lib/apolloClient'
import '../styles/globals.css'

function MyApp({ Component, pageProps }: AppProps) {
  const client = initializeApollo()
  return (
    <ApolloProvider client={client}>
      <Component {...pageProps} />
    </ApolloProvider>
  )
}

export default MyApp
import Link from 'next/link'
import { useQuery } from '@apollo/client'
import { GET_USERS } from '../queries/queries'
import { GetUsersQuery } from '../types/generated/graphql'
import { Layout } from '../components/Layout'

const FetchMain = () => {
  // useQueryの引数には実行したいクエリのコマンドを入れる
  // ジェネリクスでGetUsersQueryのデータ型定義
  const { data, error } = useQuery<GetUsersQuery>(GET_USERS, {
    // useQueryが実行される度にGraphQLサーバに毎回アクセスする。最新のデータを取得しキャッシュに格納してくれる。
    fetchPolicy: 'network-only',
    // 通信中はキャッシュにあるデータを表示し最新のデータが取得できたら上書きする
    // fetchPolicy: 'cache-and-network',
    // 初回のデータ取得以降はキャッシュのデータを表示する。デフォルトではcache-firstが利用される。
    // fetchPolicy: 'cache-first',
    // キャッシュを利用しない
    // fetchPolicy: 'no-cache',
  })
  if (error)
    return (
      <Layout title="Hasura fetchPolicy">
        <p>Error: {error.message}</p>
      </Layout>
    )
  return (
    <Layout title="Hasura fetchPolicy">
      <p className="mb-6 font-bold">Hasura main page</p>
      {data?.users.map((user) => {
        return (
          <p className="my-1" key={user.id}>
            {user.name}
          </p>
        )
      })}
      <Link href="/hasura-sub">
        <a className="mt-6">Next</a>
      </Link>
    </Layout>
  )
}

export default FetchMain