apollo-client
apollo-client copied to clipboard
Cannot modify @client field with cache.modify
Intended outcome:
Calling cache.modify should modify the
@client` field in the cache
Actual outcome:
The cache.modify call returns false, the field is not updated in the cache
How to reproduce the issue:
This is what I have:
export const GET_CREATORS = gql`
query GetCreators($limit: Limit) {
creators(limit: $limit) {
edges {
node {
id
name
profileImageUrl
isFollowing @client
}
}
}
}
`;
const typeDefs = gql`
extend type Creator {
isFollowing: Boolean!
}
`;
new ApolloClient({
...
cache: new InMemoryCache({
typePolicies: {
Creator: {
fields: {
isFollowing: {
read(_, { cache, readField}) {
const creatorId: string | undefined = readField('id');
if (!creatorId) return false;
const cachedFollows: GetMyCreatorFollows | null = cache.readQuery({
query: MY_CREATOR_FOLLOWS,
});
return cachedFollows?.myCreatorFollows.includes(creatorId) ?? false;
},
},
},
},
...
In my mutation's update
I do:
const res = cache.modify({
id: cache.identify({
__typename: 'Creator',
id: creatorId,
}),
fields: {
isFollowing() {
return true;
},
},
});
The cache modify call fails. It only works if the field is not a @client
defined field.
Versions
System:
OS: macOS 12.3
Binaries:
Node: 16.14.2 - ~/.nvm/versions/node/v16.14.2/bin/node
Yarn: 1.22.18 - ~/ntwrk/ntwrk-mobile/node_modules/.bin/yarn
npm: 8.5.0 - ~/.nvm/versions/node/v16.14.2/bin/npm
Browsers:
Chrome: 102.0.5005.61
Safari: 15.4
npmPackages:
@apollo/client: 3.4.17 => 3.4.17
apollo: ^2.34.0 => 2.34.0
I suspect the immediate issue here is that cache.modify
currently only works for fields that explicitly exist in the cache (so, for example, it can't add new fields). Since isFollowing
is a "virtual" field with only a read
function, cache.modify
effectively doesn't see it. I think I agree this is a bug, so I'm not defending this behavior, just describing it.
This seems fixable, because we know the cache.modify
call is attempting to modify isFollowing
, and the InMemoryCache
knows that there's a custom read
function defined for the Creator.isFollowing
field. Even calling the cache.modify
callback with an undefined value would work for your code. I think that might be the right answer, in fact, as opposed to calling the read
function to obtain an existing value, since cache.modify
is intended to operate on the internal cache data, pre-read
, so it might be strange to feed it the result of calling read
.
However, you may want to think about where you expect that true
return value to be stored, since your read
function doesn't currently do anything with the existing _
value. The easiest answer (I think) is to modify your read
function so it returns the existing
value (first parameter) if defined, and only falls back to the MY_CREATOR_FOLLOWS
subquery if existing
is undefined. That way, your cache.modify
code should work, by explicitly setting the internal isFollowing
field value to true
.
@benjamn You are correct, this is what's happening. However, the first parameter is always undefined. I thought that returning its default value would implicitly store it in the cache. I had to modify my read so it returns the cached value if defined, otherwise reads it and explicitly saves it. Is that the expected behavior?
Is there any workaround for this? I was hoping to manage a simple boolean flag using a local-only field. According to the docs that should be possible without typePolicies
because I just want to read from the cache directly, but I’m not sure if I still need to define a default of false
somewhere. I couldn’t get that approach to work with any of cache.modify
, cache.writeQuery
or cache.updateFragment
though 😞
Running into a similar issue with updateFragment
. After the first updateFragment
call, subsequent calls to updateFragment
act as if previous calls never happened, even though the response from the updateFragment
shows the data has been updated. My cache is persisted with MMKV.
Same issue here! @benjamn any updates about this? Any way to update a local field without reactive variables?
No one is looking into this? Same issue for me
Same issue. It would be very useful for us ...
In our case, we need to initialize the client fields with some values then to make updates by cache.modify, but I see that it's not working like this. The modify works only with non @client fields
Facing the same issue
Same issue here. If intentionally not supported would have useful to note this in the docs, spent a bunch of time trying to figure out where I was going wrong
Would like to see this fixed.
We are facing the same issue, has anyone been able to find a workaround for this?