admin管理员组文章数量:1323716
My situation has 4 ponents nested within each other in this order: Products
(page), ProductList
, ProductListItem
, and CrossSellForm
.
Products
executes a graphql query (using urql) as such:
const productsQuery = `
query {
products {
id
title
imageSrc
crossSells {
id
type
title
}
}
}
`;
...
const [response] = useQuery({
query: productsQuery,
});
const { data: { products = [] } = {}, fetching, error } = response;
...
<ProductList products={products} />
products
returns an array of Products
that contains a field, crossSells
, that returns an array of CrossSells
. Products
is propagated downwards to CrossSellForm
, which contains a mutation query that returns an array of CrossSells
.
The problem is that when I submit the crossSellForm the request goes through successfully but the crossSells
up in Products
does not update, and the UI reflects stale data. This only happens when the initial fetch up in Products
contains no crossSells
, so the initial response looks something like this:
{
data: {
products: [
{
id: '123123',
title: 'Nice',
imageSrc: '',
crossSells: [],
__typename: "Product"
},
...
]
}
}
}
If there is an existing crossSell
, there is no problem, the ui updates properly and the response looks like this:
{
data: {
products: [
{
id: '123123',
title: 'Nice',
imageSrc: '',
crossSells: [
{
id: 40,
title: 'Nice Stuff',
type: 'byVendor',
__typename: 'CrossSell'
}
],
__typename: "Product"
},
...
]
}
}
}
I read up a bit on urql's caching mechanism at / and from what I understand it uses a document cache, so it caches the document based on __typename
. If a query requests something with a the same __typename
it will pull it from the cache. If a mutation
occurs with the same __typename
it will invalidate all objects in the cache with that __typename
so the next time the user fetches an object with that __typename
it will execute a network request instead of cache.
What I think is going on is in the initial situation where there are products
but no crossSells
the form submission is successful but the Products
page does not update because there is no reference to an object with __typename
of CrossSell
, but in the second situation there is so it busts the cache and executes the query again, refreshes products and cross-sells and the UI is properly updated.
I've really enjoyed the experience of using urql hooks with React ponents and want to continue but I'm not sure how I can fix this problem without reaching for another tool.
I've tried to force a re-render upon form submission using tips from: How can I force ponent to re-render with hooks in React? but it runs into the same problem where Products
will fetch from the cache again and crossSells
will return an empty array. I thought about modifying urql's RequestPolicy to network only, along with the forced re-render, but I thought that would be unnecessarily expensive to re-fetch every single time. The solution I'm trying out now is to move all the state into redux, a single source of truth so that any update to crossSells
will propagate properly, and although I'm sure it will work it will also mean I'll trade in a lot of the convenience I had with hooks for standard redux boilerplate.
How can I gracefully update Products
with crossSells
upon submitting the form within CrossSellForm
, while still using urql and hooks?
My situation has 4 ponents nested within each other in this order: Products
(page), ProductList
, ProductListItem
, and CrossSellForm
.
Products
executes a graphql query (using urql) as such:
const productsQuery = `
query {
products {
id
title
imageSrc
crossSells {
id
type
title
}
}
}
`;
...
const [response] = useQuery({
query: productsQuery,
});
const { data: { products = [] } = {}, fetching, error } = response;
...
<ProductList products={products} />
products
returns an array of Products
that contains a field, crossSells
, that returns an array of CrossSells
. Products
is propagated downwards to CrossSellForm
, which contains a mutation query that returns an array of CrossSells
.
The problem is that when I submit the crossSellForm the request goes through successfully but the crossSells
up in Products
does not update, and the UI reflects stale data. This only happens when the initial fetch up in Products
contains no crossSells
, so the initial response looks something like this:
{
data: {
products: [
{
id: '123123',
title: 'Nice',
imageSrc: 'https://image.',
crossSells: [],
__typename: "Product"
},
...
]
}
}
}
If there is an existing crossSell
, there is no problem, the ui updates properly and the response looks like this:
{
data: {
products: [
{
id: '123123',
title: 'Nice',
imageSrc: 'https://image.',
crossSells: [
{
id: 40,
title: 'Nice Stuff',
type: 'byVendor',
__typename: 'CrossSell'
}
],
__typename: "Product"
},
...
]
}
}
}
I read up a bit on urql's caching mechanism at https://formidable./open-source/urql/docs/basics/ and from what I understand it uses a document cache, so it caches the document based on __typename
. If a query requests something with a the same __typename
it will pull it from the cache. If a mutation
occurs with the same __typename
it will invalidate all objects in the cache with that __typename
so the next time the user fetches an object with that __typename
it will execute a network request instead of cache.
What I think is going on is in the initial situation where there are products
but no crossSells
the form submission is successful but the Products
page does not update because there is no reference to an object with __typename
of CrossSell
, but in the second situation there is so it busts the cache and executes the query again, refreshes products and cross-sells and the UI is properly updated.
I've really enjoyed the experience of using urql hooks with React ponents and want to continue but I'm not sure how I can fix this problem without reaching for another tool.
I've tried to force a re-render upon form submission using tips from: How can I force ponent to re-render with hooks in React? but it runs into the same problem where Products
will fetch from the cache again and crossSells
will return an empty array. I thought about modifying urql's RequestPolicy to network only, along with the forced re-render, but I thought that would be unnecessarily expensive to re-fetch every single time. The solution I'm trying out now is to move all the state into redux, a single source of truth so that any update to crossSells
will propagate properly, and although I'm sure it will work it will also mean I'll trade in a lot of the convenience I had with hooks for standard redux boilerplate.
How can I gracefully update Products
with crossSells
upon submitting the form within CrossSellForm
, while still using urql and hooks?
- I dug a bit more and found a similar issue in the repo's github: github./FormidableLabs/urql/issues/212 There seems to be a normalized cache exchange under development that can replace the default one in urql: github./FormidableLabs/urql-exchange-graphcache. I briefly looked into it but it seemed to require a bit more configuration out of the box for my use-case and I decided that using redux would be simpler. – Kyle Truong Commented Sep 7, 2019 at 21:09
1 Answer
Reset to default 8core contributor here
本文标签:
版权声明:本文标题:javascript - How do I update the grapqhl cache with urql upon a mutation, where the initial query response does not include the 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742125160a2421905.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论