This article describes cache setup and configuration. To learn how to interact with cached data, see Reading and writing data to the cache.
InitializationCreate an InMemoryCache
object and provide it to the ApolloClient
constructor, like so:
The InMemoryCache
constructor accepts a variety of configuration options.
You can configure the cache's behavior to better suit your application. For example, you can:
Customize the format of a particular type's cache ID
Customize the storage and retrieval of individual fields
Define polymorphic type relationships for fragment matching
Define patterns for pagination
Manage client-side local state
To customize cache behavior, you provide a configuration object to the InMemoryCache
constructor. This object supports the following fields:
You can customize how the InMemoryCache
generates cache IDs for individual types in your schema (see the default behavior). This is helpful especially if a type uses a field (or fields!) besides id
or _id
as its unique identifier.
To accomplish this, you define a TypePolicy
for each type you want to customize. You specify all of your cache's typePolicies
in the options
object you provide to the InMemoryCache
constructor.
Include a keyFields
field in relevant TypePolicy
objects, like so:
This example shows a variety of typePolicies
with different keyFields
:
The Product
type uses its upc
field as its identifying field.
The Person
type uses the combination of both its name
and email
fields.
The Book
type includes a subfield as part of its cache ID.
The ["name"]
item indicates that the name
field of the previous field in the array (author
) is part of the cache ID. The Book
's author
field must be an object that includes a name
field for this to be valid.
A valid cache ID for the Book
type has the following structure:
The AllProducts
type illustrates a special strategy for a singleton type. If the cache will only ever contain one AllProducts
object and that object has no identifying fields, you can provide an empty array for its keyFields
.
The Store
type provides an example of how you can disable normalization by setting the keyFields to false
The Location
type provides an example of using custom fuction given object and runtime context to calculate what fields should be used for the key field selection.
Keep in mind that the first argument here is a reference to the record that will be written. As such, it does NOT include subselected fields, only scalar fields, and it contains aliases from the operation. If you need to read the real type you can use context.storeObject
. To read even more indepth about how this function can work the best source will be our own test cases for the cache policies
If an object has multiple keyFields
, the cache ID always lists those fields in the same order to ensure uniqueness.
Note that these keyFields
strings always refer to the canonical field names defined in the schema. This means that ID computation is not sensitive to field aliases.
If you define a custom cache ID that uses multiple fields, it can be challenging to calculate and provide that ID to methods that require it (such as cache.readFragment
).
To help with this, you can use the cache.identify
method to calculate the cache ID for any normalized object you fetch from your cache. See Obtaining an object's custom ID.
If you need to define a single fallback keyFields
function that isn't specific to any particular __typename
, you can use the dataIdFromObject
function that was introduced in Apollo Client 2.x:
The
dataIdFromObject
API is included in Apollo Client 3 to ease the transition from Apollo Client 2.x.
Notice that the above function still uses different logic to generate keys based on an object's __typename
. In a case like this, you should almost always define keyFields
arrays for the Product
and Person
types via typePolicies
.
This code also has the following drawbacks:
It's sensitive to aliasing mistakes.
It does nothing to protect against undefined object properties.
Accidentally using different key fields at different times can cause inconsistencies in the cache.
After creating an InMemoryCache
instance, you can use the addTypePolicies
method to add or modify type policies.
Here is an example of how to use the addTypePolicies
method:
The code creates an InMemoryCache
with a custom type policy for the Person
type. The type policy specifies that if the name
field is not available in the cache, it should return a default value of "UNKNOWN NAME" and converts it to uppercase.
Then, the code adds an additional type policy to the cache using cache.policies.addTypePolicies
. This new type policy is related to the Person
type and its email
field. The custom read function specifies that if the email field is not available in the cache, it should return a default value of "unknown@example.com ".
Overall, the code sets up caching behaviors for the Person
type, ensuring that default values are provided for the name
and email
fields if they are not present in the cache.
You can instruct the InMemoryCache
not to normalize objects of a particular type. This can be useful for metrics and other transient data that's identified by a timestamp and never receives updates.
To disable normalization for a type, define a TypePolicy
for the type (as shown in Customizing cache IDs) and set the policy's keyFields
field to false
.
Objects that are not normalized are instead embedded within their parent object in the cache. You can't access these objects directly, but you can access them via their parent.
TypePolicy
fields
To customize how the cache interacts with specific types in your schema, you can pass the InMemoryCache
constructor an object that maps __typename
strings to TypePolicy
objects.
A TypePolicy
object can include the following fields:
In addition to keyFields
, a TypePolicy
can indicate that its type represents the root query, mutation, or subscription type by setting queryType
, mutationType
, or subscriptionType
to true
:
The cache usually obtains __typename
information by adding the __typename
field to every query selection set it sends to the server. It could technically use this same method for the outermost selection set of every operation, but the __typename
s of the root query and mutation are almost always "Query"
and "Mutation"
, so the cache assumes those common defaults unless instructed otherwise in a TypePolicy
.
For most objects in a graph, the __typename
field is vital for proper identification and normalization. For the root query and mutation types, the __typename
is not nearly as useful or important, because those types are singletons with only one instance per client.
fields
property
The final property within TypePolicy
is the fields
property, which enables you to customize the behavior of individual cached fields.
Previous
Caching in Apollo Client
Next
Reading and writing data to the cache
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4