Apollo Client で SSR する
これは FOLIO Advent Calendar 2018 10日目の記事です。
Apollo Client
GraphQLサーバーと通信するためのクライアントサイドライブラリです。
GraphQLって何?って人は公式ドキュメントとかを読むと良いと思います。
ReactでApollo Client( react-apollo )を使用すると次のように書けます。
Server-side rendering with Apollo
Apollo Client を使用してSSR するにはサーバー側で次の2つの処理を行います。これはReduxを使用してSSRするときとおおよそ同じです。
- サーバーサイドでAPIにアクセスしStoreを共有する
- サーバーサイドでHTMLを生成する
Store rehydration
サーバーサイドでクエリを実行できるアプリケーションの場合、データの初期状態を設定できます。
次のようなscriptタグを記述することでサーバー側で定義した初期状態をクライアントサイドで受け取ることができます。
それをInMemoryCacheに渡します。
クライアントサイドでUIがレンダリングされたときにはすでにデータがストアに格納されているため、即座にデータを表示することができます。
Server-side rendering
react-apollo に組み込まれたレンダリング関数を使用して、アプリケーション全体をレンダリングします。これらの関数は、コンポーネントツリーをレンダリングするために必要なすべてのクエリを取得してくれます。通常はExpressなどのHTTPサーバー内でこれらの機能を使用します。
Apollo ClientでSSRする際は次の2つのことに注意する必要があります。
- 各クエリの結果を一度だけ取得したいので、ssrMode:trueオプションをApollo Clientコンストラクタに渡して force-fetching が繰り返されるのを避けます。
- 複数のリクエストに対してリクエストごとに新しいクライアントまたはStoreインスタンスを作成する必要があります。
そうしないと古いデータが残ってしまい、認証に問題が発生する可能性があります。
Rendering
react-apollo には2つのレンダリング関数が用意されています。
getDataFromTree()
この関数はReactツリーをレンダリングするために必要なクエリを決定し、それらをすべて実行します。ネストされたクエリがある場合は、ツリー全体を再帰的に実行します。
この関数はPromiseを返し、データの取得とStoreの準備が完了したときにそのPromiseが解決されます。そしてPromise が解決される時に Store が完全に初期化されます。
この <Html> コンポーネントの中身は次のようになります。
renderToStringWithData()
これは getDataFromTree 関数を単純化し、レンダリングする必要のあるコンテンツを文字列で返します。
Skipping queries for SSR
SSR中に意図的にQueryをスキップしたい場合は、オプションに ssr:false を渡すことができます。
おわりに
FOLIOでもBFFにGraphQLを採用するかどうか検討中なのですが、StoreのrehydrationがReduxよりも簡潔にかけるのは良いなと思いました。
このあたりは個人でも試していきたいです。
明日は sion_cojp さんの記事です。