2
0

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.

Next.jsとHasuraを連携してデータを画面に出すところまでやる(ための具体的なApollo Clientの設定)...2

Last updated at Posted at 2021-11-01

はじめに

以下のゴールを達成するため、本日はついに、Next.jsとHasuraを連携してデータを画面に出すところまでやります。

特に今回は、Next.jsでApollo Clientを使ってSSR(SSG)する仕組みの部分を見て行くと思います。

イメージ.jpg

Hasuraにあるデータやエンドポイントは既に用意してあります。

最終的なゴール

以下のような構成のアプリを作ることです。

スクリーンショット 2021-10-18 17.27.41.png

目的

  • 仕事で使っている技術のキャッチアップと復習
  • 使う可能性がある技術の理解度向上

Apollo Clientの準備

以下の2つを連携させていきます。

  • Frontend: Next.jsとApolloClient
  • Backend: HasuraのGraphqlサーバ

その前に復習

Next.js は基本的にすべてのページを Pre-rendering しますが、その中でも

- ビルド時にサーバ側でデータを取得してHTMLを生成し、リクエストに対してそれを返す SG(Static Generation)
- クライアントのリクエストに対してサーバ側でデータを取得してHTMLを生成し、返す SSR(Server Side Rendering)

があることを覚えてください。

具体的な方法はここからパクります。

Next.js公式の実例集ですね。

ここから必要な部分だけ抜き取っていきます。

それでは、コードを書いていきます。階層やファイル名も実例集を真似て作成してみましょう。

lib/apolloClient.js
lib/apolloClient.ts
import {
  ApolloClient,
  HttpLink,
  InMemoryCache,
  NormalizedCacheObject,
} from '@apollo/client'
import 'cross-fetch/polyfill'

let apolloClient: ApolloClient<NormalizedCacheObject> | undefined

console.log('apolloClient', apolloClient)

const createApolloClient = () => {
  return new ApolloClient({
    ssrMode: typeof window === 'undefined',
    link: new HttpLink({
      uri: 'https://ryosuketter-hasura-test.hasura.app/v1/graphql',
    }),
    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
}

部分的にコードの解説をします。

// | より左がapollo client お決まりのデータ型の定義です このために NormalizedCacheObject を import したんすね
// | より右が undefined つまり未定義な可能性もなきにしもあらずでっせ。という意味
let apolloClient: ApolloClient<NormalizedCacheObject> | undefined

続いて ApolloClient インスタンスを作成する関数を見てみましょう。

const createApolloClient = () => {
  return new ApolloClient({
    // typeof window は、ブラウザで実行しているかどうか?サーバー側で実行しているか?の条件判定
    // 何を実行しているかというとプリレンダリング
    ssrMode: typeof window === 'undefined',
    link: new HttpLink({
      uri: 'https://ryosuketter-hasura-test.hasura.app/v1/graphql',
    }),
    cache: new InMemoryCache(),
  })
}

ApolloClientインスタンスを作成するのに、3つの引数を必要としていますね。1つづつみていきます。

ssrModeについて

windowというのは、「まあ、ブラウザで実行している」と思ってていいです。

大抵こうなるし。

7533149b6166bf108366ee57f9ade72a.gif

そうならない

すなわち

ssrMode: true

になる場合(typeof window === 'undefined'TRUE)はサーバで実行していると思ってください。

link: new HttpLink({uri: 'ここでは作成したHasuraのAPIのエンドポイントを入力します' })

環境変数から参照しても良いです。

最後に cache ですが、これはお決まりの形(おまじない)的に覚えてください。

cache: new InMemoryCache()

次に、ApolloClientインスタンスを作成に関する初期化に関する関数をみていきます

export const initializeApollo = (initialState = null) => {
  const _apolloClient = apolloClient ?? createApolloClient()

  // For SSG and SSR always create a new Apollo Client
  // サーバーサイドで実行されるSSG, SSR, またはISRなどの、サーバーサイドで実行される場合は、常に新しい
  if (typeof window === 'undefined') return _apolloClient

  // Create the Apollo Client once in the client
  if (!apolloClient) apolloClient = _apolloClient

  return _apolloClient
}

こちらも上から見ていきましょう。

const _apolloClient = apolloClient ?? createApolloClient()

??より左辺が null | undefined なら、右辺を実行するという意味です。

全体的な処理を見ると、initializeApollo関数は、最初は、右辺(createApolloClient())が実行され新しいApolloClientインスタンスが生成され_apolloClientに代入される。

その後

それがサーバでの実行なら((typeof window === 'undefined'TRUE))で、即座に_apolloClientが返されます

変数apolloClientには何も代入していないので、

const _apolloClient = apolloClient ?? createApolloClient()

これはまた、右辺が実行され、新たなApolloClientインスタンスが生成され_apolloClientに代入されます。

サーバーで実行する限りそうなります。

その結果

// For SSG and SSR always create a new Apollo Client

このコメントが、その通りになった、という感じですね。

対して、クライアントサイドで、実行された場合を見ていきましょう。

どちらにせよ下記は実行されます。

const _apolloClient = apolloClient ?? createApolloClient()

次に、typeof window === 'undefined'FALSEになるので、この行はSKIPされます。

次に

  // Create the Apollo Client once in the client
  if (!apolloClient) apolloClient = _apolloClient

最初の実行なら apolloClientundefined で、それの!なので、TRUEになって、apolloClient_apolloClientが代入されます。

サーバで実行する場合、毎回ApolloClientインスタンスを生成し、返す。

クライアントで実行する場合、最初はサーバから取ってくるけど、次回からは、1回目にapolloClient_apolloClientが代入されるので、

return _apolloClient つまり、2回目以降は、1回目に作成したapolloClientが返されます。

これが、Next.js でサーバーサイドの処理とクライアントサイドの処理の切り分けをする上で重要になります。

これで、Apollo側の設定は終わります。

今日のところは以上です。

次は、pages配下の実装をみていきます。

アウトプット100本ノック実施中

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?