-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
read method on field's TypePolicy should allow async behaviour #383
Comments
At a superficial level, async However, you can implement a new InMemoryCache({
typePolicies: {
Person: {
fields: {
asyncName: {
read(existing, { storage }) {
if (!storage.var) {
storage.var = makeVar("unknown");
delay(100).then(() => storage.var("Foo"));
}
return storage.var();
}
}
}
}
}
}) Although this may seem a bit convoluted compared to an To make this pattern simpler, we believe we may be able to provide a helper function that would work something like this: new InMemoryCache({
typePolicies: {
Person: {
fields: {
asyncName: {
read: asyncRead(async (existing, options) => {
await delay(100);
return "Foo";
}),
}
}
}
}
}) The |
Hey @benjamn, thanks for your response! I think I finally get why The Example: const client = new ApolloClient({
client: new InMemoryCache({
typePolicies: {
Person: {
fields: {
asyncName: {
read: asyncRead(async (existing, options) => {
await delay(100);
return "Foo";
}),
},
},
},
},
}),
});
// Somewhere in a React tree under ApolloProvider
const Component = () => {
const { data, loading, error } = useQuery(gql`
query ComponentQuery {
people {
name,
asyncName @client
}
}
`)
if (loading) {
return <Loading />
}
return (
<div>
{data.name} {/** <- this will be defined */}
{data.asyncName} {/** <- this still might be `undefined` right after `loading` flips from `true` to `false` */}
</div>
);
} What I'd imagine that helper would let me do is somehow teach the client to wait for all data (remote and local) to be resolved and only then render, but unfortunately this seems not to be the case. I can't help but wonder, perhaps my use case is a bit niche and maybe it's better off handled in a custom |
I'm in a similar situation myself and the best solution I've came up so far with is, instead of
When the |
Hey @benjamn As u can see my cache is empty after all these manipulations... |
Should I do it manualy? Right? if (!storage.var) {
storage.var = makeVar(null);
get(`performer/performers?${urlQuery}`)
.then(
res => res.map(
el => ({
...el,
id: el.performerId,
__typename: 'performers'
})
)
)
.then(
data => {
storage.var(data)
cache.writeQuery({
query: getPerformers,
data: {performers: data}
})
}
)
}
return storage.var(); |
@benjamn And how I can set the |
Nevermind. I figured out. Instead of import { makeVar } from '@apollo/client'
export const asyncRead = (fn, query) => {
return (_, args) => {
if (!args.storage.var) {
args.storage.var = makeVar(undefined)
fn(_, args).then(
data => {
args.storage.var(data)
args.cache.writeQuery({
query,
data: { [args.fieldName]: data }
})
}
)
}
return args.storage.var()
}
} and then loading state will detect properly. |
i am unable to get this to work 😢 maybe a clear documentation or prepared helper function could help |
@gcofficial I have an async problem with a query field and I'm wondering if your asyncRead could help. Would be awesome if you could tell me how I would wrap this in your proposed asyncRead function:
|
Hey 👋🏻 @MarMun It will be something like this...
|
Is there a way around this for the mean time? Rather than trying to read from async storage within the cache, is it possible to use something like apollo-cache-persist so that the whole cache just gets saved to AsyncStorage and persists over app reloads? |
I attempted to migrate some resolvers over to type policy
For now I've reverted my changes and will have to stick with resolvers. Although, I've seen how the flexibility of local resolvers can be abused and agree restrictive |
Commenting here in case anybody else needs this. I recently found that returning a reactive var with import { ReadFieldFunction } from '@apollo/client/cache/core/types/common';
// this makes the cache from a field-read
const cacheId = (readField: ReadFieldFunction): string => `${readField('__typename')}:${readField('id')}`
// in your type policies
const typePolicies = {
Query: {
fields: {
SomeType: {
fields: {
yourAsyncField: {
read(existing, { readField, cache }) {
doSomethingAsync().then((result) => {
cache.modify({
id: cacheId(readField),
fields: {
yourAsyncField: result,
},
});
});
return existing;
},
},
},
},
},
},
}; We modify the cache directly on the object (assuming your field has an |
* Paraphrase @benjamn's comment for content: https://github.com/apollographql/apollo-client/issues/6852#issuecomment-674984235
* Paraphrase @benjamn's comment for content: https://github.com/apollographql/apollo-client/issues/6852#issuecomment-674984235
* Paraphrase @benjamn's comment for content: https://github.com/apollographql/apollo-client/issues/6852#issuecomment-674984235
Intended outcome:
I was trying to add a read method on a field. Inside this method I'd perform an async operation and return a promise with the data (see codesandbox below).
This was my effort to upgrade existing AC2 app to AC3 and migrate away from local resolvers.
Actual outcome:
My expected outcome was that Apollo Client would wait for that promise to resolve and only then would render data in my component. However, it accepted the returned promise, did not wait for it to settle and attached it under data in
useQuery
hook.This makes migrating away from local resolvers much much more difficult since local resolvers can wait for data to resolve before returning response where
read
from Type Policies cannot.How to reproduce the issue:
See this codesandbox's
index.js
andApp.js
fileshttps://codesandbox.io/s/apollo-type-policy-async-read-3d1fj?file=/src/index.js
Versions
The text was updated successfully, but these errors were encountered: