Apollo Client を基礎から理解する(local state管理編)
現在のプロジェクトで Apollo Client を触り始めて約半年。いまだに「Apollo Client完全理解した!」 と言えるレベルに至っていないのですが、Apollo Client の最難関「キャッシュ」をはじめとした基本的な使い方についてまとめてみました!
間違っている内容やさらに良い方法等あれば、コメント欄にて(優しく)ご指摘いただけるととても嬉しいです。
- Apollo Client を基礎から理解する(キャッシュの仕組み編)
- Apollo Client を基礎から理解する(QueryとMutationのhooksの使い方編)
- Apollo Client を基礎から理解する(local state管理編) 👈
はじめに
Apollo Client3から新たに、ローカルデータを管理する便利な機能としてtypePolicies
とReactive variables
などが追加されました。
本記事では、typePolicies
とReactive variables
の具体的な使い方についてまとめていきます。
参考
・Reactive variables - Apollo GraphQL Docs
・TypePolicy fields - Apollo GraphQL Docs
Reactive variables とは
Reactive variables
はキャッシュ(=GraphQLで取得したデータを正規化したもの)から切り離されているため、任意の型や構造のデータを保持することができ、GraphQLスキーマなしでアプリケーションのどこからでも参照・更新することができます。そのため、ReduxやRecoilなどの状態管理ライブラリを使用せずとも、グローバルな状態管理をもApollo Client一つで管理することができます。
具体的な使用方法
Reactive variables
の具体的な使用方法について解説していきます。
1.リアクティブ変数を使うための関数を作成
makeVarメソッドを使用してリアクティブ変数を使うための関数を作成します。
import { makeVar } from '@apollo/client'
// 現在のログイン情報を保持するリアクティブ変数。引数に初期値(false)を指定します。
export const isLoggedIn = makeVar(false)
2. リアクティブ変数を読み取る
リアクティブ変数を読み取るには、以下の2つの方法があります。
注意点として、両者にはリアクティブ変数が更新された時のレンダリングの挙動に違いがあります。
1で作成した関数の引数をなしで呼び出す
リアクティブ変数が更新された場合、リアクティブ変数を読み取っているコンポーネントは再レンダリングはされない
import { isLoggedInVar } from 'apollo/store'
export const Home = () => {
const isLoggedIn = isLoggedInVar()
return (
<>{isLoggedIn ? "ログイン" : "ログアウト"}<>
)
}
1で作成した関数をuseReactiveVarの引数に指定する
リアクティブ変数が更新された場合、リアクティブ変数を読み取っているコンポーネントは再レンダリングされる
import { useReactiveVar } from '@apollo/client';
import { isLoggedInVar } from 'apollo/store'
export const Home = () => {
const isLoggedIn = useReactiveVar(isLoggedInVar)
return (
<>{isLoggedIn ? "ログイン" : "ログアウト"}<>
)
}
参考:Storing local state in reactive variables - Apollo GraphQL Docs
3. リアクティブ変数を変更する
1で作成した関数の引数に更新する値を指定します。
import { isLoggedInVar } from 'apollo/store'
isLoggedInVar(true)
typePolicies とは
typePolicies
では、GraphQLスキーマの各タイプをカスタマイズしたり、キャッシュの識別子を変更したりなどを設定することができます。
具体例を交えながら説明していきます。
使用するGraphQLスキーマ
# ルートオペレーション
type Query {
"商品一覧"
items: [Item!]!
}
# Type
"商品の型"
type Item {
id: Int!
name: String!
price: Int!
}
キャッシュデータをカスタマイズする
商品の価格の末尾に「円」をつけて表示する方法です。
const cache = new InMemoryCache({
typePolicies: {
// ここにカスタマイズしたいTypeを指定します
Item: {
fields: {
price: {
read(price) {
return price + '円'
}
}
},
},
},
})
Reactive variables と一緒に使う
リアクティブ変数と一緒に使うことで、リアクティブ変数が変更される度に依存する全てのアクティブなクエリが自動的に更新されます。
useQueryを使う方法
import { makeVar } from '@apollo/client'
import { isLoggedInVar } from 'apollo/store'
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
// Query(isLoggedIn)を指定します
isLoggedIn: {
read() {
return isLoggedInVar()
}
}
},
},
},
})
import { currentUserVar } from 'apollo/store'
import { gql, useQuery }from "@apollo/client";
// クライアントのみで使用するクエリ
const IS_LOGGED_IN = gql`
query isLoggedIn {
isLoggedIn @client
}
`;
export const Home = () => {
const { isLoggedIn } = useQuery(IS_LOGGED_IN).data;
return (
<>{isLoggedIn ? "ログイン" : "ログアウト"}<>
)
}
useReactiveVarを使う方法
@client
を用いたGraphQLのクエリの記述は不要となり、シンプルな書き方ができます。
その代わり、Apollo Client Devtools
で確認することができなくなってしまいます。
import { makeVar } from '@apollo/client'
import { isLoggedInVar } from 'apollo/store'
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
// Query(isLoggedIn)を指定します
isLoggedIn: {
read() {
return isLoggedInVar()
}
}
},
},
},
})
import { useReactiveVar } from '@apollo/client';
import { currentUserVar } from 'apollo/store'
export const Home = () => {
const currentUser = useReactiveVar(currentUserVar)
return (
<>{currentUser}<>
)
}
キャッシュの識別子を変更する
「キャッシュの仕組み編」の記事に記載しております。
まとめ
以上、Reactive variablesとtypePoliciesについてまとめてみました。
この記事が何かお役立ていただけましたら幸いです。
Discussion