ALLSPICE

スパイスファクトリー株式会社のメンバーが運営するWeb開発メディア

React + GraphQL + Apollo Client ローカルステートの管理方法の参考例

React + GraphQL + Apollo Client ローカルステートの管理方法の参考例

Posted by spice_lin | |システム開発

スパイスファクトリー株式会社、エンジニアのリンです。
スパイスファクトリーの詳しいサービスはシステム開発に関するページをご覧ください。

近年、React + GraphQL + Apollo Client を組み合わせた開発の人気の高まりと共に、React + GraphQL + Apollo Client の導入について紹介する記事が増えてきています。

React + GraphQL + Apollo Client

2020 state of js data layer 部門GraphQLだけでなく、GraphQL関連のpackage (Apollo Client)も注目されてます

その中で、GraphQL のつなぎ込みや Apollo が提供する hook などの記事は多くありますが、ローカルステートの管理についての紹介はまだ多くありません。

そのため、Apollo Client を使ったときのローカルステートの管理をどのように設計すべきか参考例と共にまとめていきます。
尚、こちらの記事は、React、redux、GraphQL の知識をお持ちの方を対象に説明を進めます。

Apollo Clientが担う役割によって運用方法やパッケージが異なる

まず、Apollo Client がアプリケーション内でどのような役割を担うか考えてみます。
その違いによって、ローカルステートの管理の仕方、または運用するパッケージも異なってくるためです。

基本的には、Apollo Client がアプリケーション内で担う役割については、以下の2つになります。

  • 単なるGraphQLのAPIサーバーへのつなぎ込み及び取得したデータのキャッシュ化
  • アプリ全体のデータのコアとしての役割

Apollo Client を単なる GraphQL のAPIサーバーへのつなぎ込み、そして取得したデータをキャッシュ化してくれるツールと考える場合は、Apollo Client以外での状態管理が必要になります。

Apollo Client をアプリ全体のデータのコアと考える場合は、Apollo Client の API でローカルステートも管理していきます。

以下、Apollo Client 以外で状態管理する場合と、Apollo Client の API でローカルステートも管理する場合の、それぞれの方針について詳しく見てきます。

Apollo Client以外で状態管理する場合

Apollo Client以外で状態管理をするなら、GraphQL や Apollo Client を利用しないアプリケーションと大きな違いは無いと考えます。
そのため一般的によく使われる下記のような状態管理のライブラリが利用できます。

  • redux
  • React Context
  • その他(MobX…など)

考慮すべき点

Apollo Client 以外で状態管理する場合は以下の留意点があります。
まず、GraphQL に関連するデータが ApolloClient 側に、ローカルステートは他のライブラリにそれぞれ保持されるため、管理し辛い状況が出てきます。
また、データが二重管理になる可能性や、パッケージ数が増えるといった点も考慮する必要があるでしょう。

これらの問題を解決するには、予めルールを作りデータが重複しないよう工夫することがまず考えられます。
その他、Apollo Client の代替として URQL を利用するのもひとつの方法でしょう。

https://formidable.com/open-source/urql/

Apollo ClientのAPIで状態管理する場合

Apollo Client の API で状態管理する場合について考えていきます。
尚、Apollo Client はローカルステートに関して4種類の API を提供しています。

Apollo Clientのcache にデータを直接書き込む

Apollo Client の cache にデータを直接書き込んで、GraphQL の形で呼び出します。
以下のような記述で実現可能になります。

呼び出す

graphQL の変数名の後ろに `@client`を追加すると、Apollo Client はローカルステートとして認識してくれます。


const IS_LOGGED_IN = gql`
  query IsUserLoggedIn {
    isLoggedIn @client
  }
`;

 

書き込む


cache.writeQuery({
  query: IS_LOGGED_IN,
  data: {
    isLoggedIn: // ログインの判断処理 e.g. !!localStorage.getItem('token'),
  },
});

 

reactive variableを利用する(Apollo 3 系以降)

reactive variable (Apollo 3 系以降)は、どこでも使えるグローバル変数です。
以下ソースコード例です。

グローバル変数作成


import { makeVar } from '@apollo/client';
const isLoggedInVar = makeVar(false);

 

呼び出す


console.log(isLoggedInVar());
// output: false

 

書き込む


isLoggedInVar(true)
console.log(isLoggedInVar());
// output: true

 

type policiesを利用する(Apollo 3 系以降)

type policies (Apollo 3 系以降)は、GraphQL (Query) を通じて、ローカルステートを呼び出し、type policies が対応するデータを返します。

定義する

ローカルステートの中に `isLoggedIn` が使われる時にどういう値を返すかのを定義します。後ほど GraphQL で isLoggedIn も呼び出すことができます。


export const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        isLoggedIn: {
          read() {
            return true;
          }
        }
      }
    }
  }
});

 

呼び出す


const IS_LOGGED_IN = gql`
  query IsUserLoggedIn {
    isLoggedIn @client
  }
`;

 

local resolverを利用する(Apollo Client 3系前で利用可能)

3系以前で主流だった方法のひとつです。
3系以降でも使えるのですが、廃止予定となっておりかつ API の更新が既に停止しているため、ご注意ください。
尚、API の更新が早かったり、コンセプト自体が他の既存のライブラリーとやや異なるため、学習コストが高いことが懸念点です。

プロジェクトの状況によって、適するローカルステートの管理方法は異なる

React + GraphQL + Apollo Client でのローカルステートの管理の方法をまとめてみました。
プロジェクトの状況によって、適するローカルステートの管理方法は異なってくると思います。

この記事では Apollo Client が担う役割に基づいて2つの実装方針をまとめましたが、他にも色々な観点があります。
例えば、既に redux を導入しているプロジェクトだと、無理に Apollo Client APIに変更することはあまりメリットがないかもしれません。
また、Apollo Client の API がまだ定まっていないという観点から、Apollo Client の API を導入しないと考えるのもまた合理的だと思います。
私自身は、パッケージを減らすことができ、構造上 SSOT(single source of truth) のコンセプトに近いという視点から、Apollo Client の API を利用しています。

ケースバイケースで適するローカルステートの管理方法が何かを考え、取り組んでいくことが必要でしょう。

最後に

また、弊社では開発からサービスの運用まで、幅広くご支援させていただいております。
是非一度お気軽にお問い合わせください。

また、詳しいサービス内容に関しては、当社ホームページのアジャイルシステム開発に関するページをご参照ください。

CONTACT

無料相談はこちらから
 

このエントリーをはてなブックマークに追加
About The Author

spice_lin

何かお困りのことはありませんか?無料でご相談を承っております!