addTypename: true
cacheKeyRoot: CacheKeyNode {children: Map(89), key: {…}}
config: {fragmentMatcher: HeuristicFragmentMatcher, dataIdFromObject: ƒ, addTypename: true}
data: DepTrackingCache {data: {…}, depend: ƒ}
maybeBroadcastWatch: ƒ optimistic()
optimistic: []
silenceBroadcast: true
storeReader: StoreReader {cacheKeyRoot: CacheKeyNode, keyMaker: QueryKeyMaker, executeStoreQuery: ƒ, executeSelectionSet: ƒ}
storeWriter: StoreWriter {}
typenameDocumentCache: Map(26) {{…} => {…}, {…} => {…}, {…} => {…}, {…} => {…}, {…} => {…}, …}
watches: Set(13) {{…}, {…}, {…}, {…}, {…},
・Storeする前にそれぞれのオブジェクト個々のオブジェクトに分割して、識別子をふって、フラット化されたデータ構造に格納する
・オブジェクトに__typenameが見つかった場合、一意の識別子としてidと_idを使う
・もしid、_idが記述されていない、もしくは__typenameが記述されていない場合、フォールバックとしてrootのqueryとしてallPeopleから返されたオブジェクトはROOT_QUERY.allPeople.0のようにROOT_QUERYにパスがつくられる
このデフォルトの設定はInMemoryCacheのコンストラクタ上にdataIdFromObjectで設定できる
・データがキャッシュにない場合Errorをthrowする ・queryは適切なキャッシュがない場合serverにリクエストをする場合があるがreadQeuryはapollo serverにrequestしない。キャッシュに対してリクエストする ・もしreadQueryで読みたいリクエストの全てのデータがキャッシュ上にない場合はErrorが返され、もし全てのデータがある場合はキャッシュが返されます。自分が知っているデータを読み込むようにしてください
readQueryはrootのquery型からのリクエストを可能にするが、
readFragmentはどこのnodeからのリクエストも可能にする
const todo = client.readFragment({
id: ..., // `id` is any id that could be returned by `dataIdFromObject`.
fragment: gql`
fragment myTodo on Todo {
id
text
completed
}
`,
});最初の引数の
idは読み込みたいキャッシュのidで、dataIdFromObjectから返されたidでなくてはならない
const client = new ApolloClient({
...,
dataIdFromObject: object => object.id,
});このように設定すればidが振られる。
が多くの場合デフォルトの__typename。
idの場合はこのようにキャッシュに対してリクエストとする
const todo = client.readFragment({
id: '5',
fragment: gql`
fragment myTodo on Todo {
id
text
completed
}
`,
});注:ほとんどの人はdataIdFromObjectのIDに__typenameを追加します。
これを行う場合は、フラグメントを読むときに__typenameを追加することを忘れないでください。
そのため、例えばあなたのIDはTodo_5であって5だけではないかもしれません。
・もし、cache上にidが振られてなかったら nullが返ってくる
・もし、cache上にidが存在してもtextフィールド(上記のリクエストにあるtextフィールド)が存在していない場合 エラーが返ってくる
いいところは
idさえ指定すればキャッシュのどこからでもそれを読み込むことができること。
例えばそれで得たtodoは
({ todo(id: 5) { ... } }),
からのそれかもしれないし、
リストの ({ todos { ... } }),
からのそれかもしれないし
(mutation { createTodo { ... } }).
で得たそれかもしれない
キャッシュに対して変更できる、ただ忘れてはいけないのはserverに対しての変更ではないこと リロードするとwriteQueryとwirteFragmentで書き込んだキャッシュは消えてしまう
・シグネチャ(引数の型、引数の数、返り値の型)はreadQueryとreqdFragmentと同じ
completedフラグを更新したい場合はこう
client.writeFragment({
id: '5',
fragment: gql`
fragment myTodo on Todo {
completed
}
`,
data: {
completed: true,
},
});この値を観測しているsubscriberはこのアップデートするためにレンダーが走ります
もしfetchしたtodoListデータにtodoを追加したい場合
const query = gql`
query MyTodoAppQuery {
todos {
id
text
completed
}
}
`;
const data = client.readQuery({ query });
const myNewTodo = {
id: '6',
text: 'Start using Apollo Client.',
completed: false,
};
client.writeQuery({
query,
data: {
todos: [...data.todos, myNewTodo],
},
});例えば、 こちらのようなTodoを作るmutationを実行して
mutation TodoCreateMutation($text: String!) {
createTodo(text: $text) {
id
text
completed
}
}こちらで
query TodoAppQuery {
todos {
id
text
completed
}
}キャッシュに対して更新する場合。 (mutationの終わりに、実際にクエリを送信せずにmutationが終了した後にもう一度TodoAppQueryを送信したように、クエリに新しいtodoを含めるようにします。)
// We assume that the GraphQL operations `TodoCreateMutation` and
// `TodoAppQuery` have already been defined using the `gql` tag.
GraphQLのオペレーションに `TodoCreateMutation`と`TodoAppQuery`をすでに持ち、`gql`tagを使って定義されているものとします
const text = 'Hello, world!';
client.mutate({
mutation: TodoCreateMutation,
variables: {
text,
},
update: (proxy, { data: { createTodo } }) => {
// Read the data from our cache for this query. //キャッシュからこのquery(TodoAppQuery)を得る
const data = proxy.readQuery({ query: TodoAppQuery });
// Add our todo from the mutation to the end. //todoにmutationから戻りをcacheで得たmutationする前のデータに付け加える
data.todos.push(createTodo);
// Write our data back to the cache. //キャッシュに対して、dataに置き換えて、書き込む
proxy.writeQuery({ query: TodoAppQuery, data });
},
});・proxyオブジェクトは他の変更に邪魔されないトランザクションを提供し、最後まで書き込みを完結させる
optimisticResponseをオプションでしたいした場合2回呼び出される
1回目はmutationが行われた直後に、そのデータと共に、
2回目は1回目のそれが行われた後に実際に本物のデータが返ってくる (WIP)
彼らは違うことをします。 optimisticResponseはサーバーからの応答を予測します。
あなたがすでにcacheにあるノードを更新しようとしているなら、これを使う
update更新機能はあなたのstoreを完全にコントロールさせます。
たとえば、新しいノードを作成した場合は、それを関連クエリに追加する必要があります。
その新しい実体として、Apolloはそれをどうするべきか自動的には知りません。
他の2つの答えを拡大すると、区別しているのは、「更新中」のものがすでにキャッシュに存在するかどうかです。
もしあなたが既存のアイテムを更新しているなら、
例えば、
ToDoアイテムのタイトルを編集するなら、
あなたはoptimisticResponseを必要とするだけです。
どうして?
キャッシュにはノードが含まれているので、
新しいノードで何か新しいことが起こったことを伝えるだけでよく、
それはすぐにUIに反映されます。
optimisticResponseは、mutationからの「即時の」結果データを提供するだけです。
2つ目のケースは、
リストに新しいTodoアイテムを追加することです。
まず、
キャッシュは新しいアイテムが作成されたことを知る必要があります。
更新属性をMutationに提供するとすぐに、キャッシュの状態を制御します。
updateはrefetchQueriesの代わりに実行されます。
つまり、キャッシュ状態を管理していることになります。
データの階層全体を再フェッチするのではなく、
updateを使用すると、
キャッシュにアクセスして必要なノードだけを変更/追加することができます。
しかし、あなたはまだmutationが終了するのを待っています。
optimisticResponseと一緒にupdateを提供すると、
即座に想定される応答を提供し、
それを個人用の更新機能に渡します。
これにより、即座にキャッシュが更新されます。
これら2つがシナリオ2でペアになっているのは、
サーバーの応答を完全に回避しているためです。
「即時」応答をしただけでは、Apolloはまだサーバーがキャッシュを更新するのを待つモードにあります。
updateを使うと、
それをハイジャックすることができ、
クライアント側でもできます。
see: https://stackoverflow.com/questions/49186523/optimisticresponse-vs-update-in-apollo-client
・update関数は複数回呼び出される可能性があるため、副作用には適していません。 ・また、プロキシ上のメソッドを非同期に呼び出すことはできません。
常に値が帰ってくることを保証している -> String!
Qeuryは並列、mutationは順次、1つ目が終わったら2つめ
__typenameは帰ってくる型を知らせるためにある- cacheをupdateするときに使われるdefaultでついてくるもの
unionTypeで帰ってくるオブジェックトに対してとの型で返ってきたか区別するために必要
Introspection ・・・shemaの情報を教えてくれるもの__shemaのゆうなもの
Normalization ・・・chache storeにいれるまえにqury結果を変換すること
- レスポンスを一意のものに区別分けて、フラットにしてstoreすること
normaraize時にidか__typenameがないとRootにキャッシュがつくられる
[Episode!]は配列のEpisode型。nullでないので必ず配列が返ってくる
fileName: [String!] -> リスト自体はnullでいいが要素はStringじゃないとダメなことを示している
参考
