-
Notifications
You must be signed in to change notification settings - Fork 787
Refetch queries on underfetch #2003
Refetch queries on underfetch #2003
Conversation
@steelbrain: Thank you for submitting a pull request! Before we can merge it, you'll need to sign the Meteor Contributor Agreement here: https://contribute.meteor.com/ |
@steelbrain thanks for your investigation 👍 |
@steelbrain We successfully tested the workaround in our projects. 💯 |
@steelbrain @jonas-arkulpa This is fantastic! We've been running into this issue and have been debating how to resolve the problem. I agree that automatically "filling in" missing fields is the wrong way to go. We've gone down the path of adding fields causing errors and applying fragments. Not great 😕. Your solution to instead refetch data is a good option, however, I wonder if the query manager could be further refactored so that an optional hook/plugin could be provided to the QM. The QM could then call the hook to delegate how best to handle a detected error. I say this since in our particular scenario, the detected field error pops up not because of direct GQL mutation but, rather, from our system running one or more queries whenever our app receives pushed system events (via websocket). Depending on the circumstance, we could either use a default refetch action (like your solution provides) or in turn perform our own custom error handling that best serves our purposes. Thoughts? For more detail of the problem we have run into, please see apollographql/apollo-client#2920 (comment) |
@mlcohen I also have a branch in The fact that Apollo React Thoughts? Edit: We could also add a prop to the |
@steelbrain Yeah, I can certainly see your point directly exposing the error to the React component. We were thinking about updating the apollo client's query manager directly instead of indirectly via a React component. Applying the hook directly against the underlying apollo client instance would provide a way for the system to "globally" handle detected field errors. This means that React components that use apollo client would not be exposed to these types of errors. The global default would be for the QM to do an automatic refetch. Your idea of adding a |
Because including Other than refetching or handling it on a component-level basis, I am curious how do you intend to handle it directly in Apollo Client? Unless, you are not using React for rendering UI. |
In our application we perform GQL queries and mutation through |
If you're calling What I'd consider the expected behavior is for the response of the mutation to simply overlay/merge into the existing cache, and then fire renders for all subscribers from the current cache state, not from the network response. |
@peisenmann While merging is possible, it's also possible that other fields may have changed Either way that cannot be done in |
@steelbrain A perfectly valid point, for sure. I'd expect in that case, if you wanted to check for those other fields, you would have them in the query part of your mutation or you would use refetchQueries to trigger the other, bigger query to be re-invoked. By excluding those fields from my mutation, I'm signaling that I don't want them updated at this time. In an application I'm working on, when a user queues up local changes that are not ready to be persisted to the server yet, we use a writeFragment to write the data back into the Apollo cache. This keeps all views up to date with the user's changes, as long as no rogue refetches are called. As you've noted, I will take my "expected behavior" points up with the other |
@peisenmann see the original issue (apollographql/apollo-client#3267). Normally the mutation payload does get merged into the cache. The code in this PR only gets activated when the mutation payload has under-fetched data, and a component is trying to render with that under-fetched data. In that case you cannot simply merge with the cache because the cache doesn't have what you need. |
@idris Ah, okay, so the original full query is not even populated in the first place. @steelbrain Apologies for wasting your time. Thanks for the PR! |
Edit: I think I’ve actually run into a different issue not necessarily related to this PR. I apologize and have reproduced it and will create a new issue from it. @idris I'm not following what your saying but am desperate to understand this behavior better as I keep running into it. @peisenmann I think this occurs in the case that the original full query is there. Someone correct me if I'm wrong, but that is the behavior I am seeing. So I'm probably overlooking something and am going to look foolish once you explain @idris, but what do you mean here exactly:
Why is that not possible? You should be able to theoretically merge any fields that were in that mutation payload into the cache and not disturb the ones that it didn't fetch no? |
Would really love to see this PR merged, it's been consistently a serious deal breaking bug for at least 10 months now... |
@felixk42 I'm close to getting this merged in, but this change could have implications on a few edge cases. Regardless, you should see more updates here today. |
@hwillson thanks for your work & your blog post! As this issue is the biggest blocker for (not only) our projects I think it clearly needs more thoughts putting into it. We are really happy to finally have a usable workaround, but it clearly is just that, a workaround. |
Thanks @jonas-arkulpa! Just a quick heads up for everyone here. I cleaned things up a bit, ran some more tests, and have had a few more discussions about this approach. While this PR does fix the original issue, we're still a bit concerned about the potential performance impact this could have on larger applications. We're currently digging a bit deeper to see if this can be resolved in another way, but we haven't ruled this potential solution out yet. Sorry for the delay all - this issue has been around for a while, and we can't wait to get it fixed, but we just want to make sure the fix doesn't cause more problems. Thanks for your patience! |
@hwillson we (me and my team, original authors of this PR) would be happy to contribute to those discussions and provide input. Happy to do that here or in Slack. IMO the more in-the-open the discussion, the quicker we can poke holes and land on something that makes sense. |
I don't know why this keeps flying under the radar or if it is deemed not important enough, it's just rather frustrating that something that so drastically changes behavior (and even breaks apps) on a minor version bump gets so little attention. |
+1 |
src/Query.tsx
Outdated
@@ -172,7 +174,7 @@ export default class Query<TData = any, TVariables = OperationVariables> extends | |||
fetchData(): Promise<ApolloQueryResult<any>> | boolean { | |||
if (this.props.skip) return false; | |||
// pull off react options | |||
const { children, ssr, displayName, skip, client, ...opts } = this.props; | |||
const { children, ssr, displayName, skip, client, disablePartialRefetch, ...opts } = this.props; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder, what is the reason to deconstruct this variable in here when you don't use it later anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dajvido To remove it from opts
: See something like https://codeburst.io/use-es2015-object-rest-operator-to-omit-properties-38a3ecffe90
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks very much for your work on this @steelbrain! We're going to move ahead with getting this merged, but we've flipped things around a bit so the partial refetch functionality is disabled by default. That will de-risk this PR a bit, and help us get this out sooner than later. If anyone in this PR objects, definitely let me know. Otherwise, the current plan is to get this launched tomorrow. Thanks again for working on this!
To line up with the React Apollo `partialRefetch` changes in apollographql/react-apollo#2003.
To line up with the React Apollo `partialRefetch` changes in apollographql/react-apollo#2003.
🎉 |
Please let me know when a new version of |
@mcmar It will be released very soon. The plan was to release it today, but we've hit a bit of a snag with a few dependency issues (unrelated to this PR). They should be resolved shortly, and the release will be pushed out right after (current guesstimate - early am tomorrow). Thanks! |
React Apollo 2.2.0 is now available. Thanks! |
Great! I upgraded to 2.2.0 and rerun my tests. Unfortunately, the issue I reported above with a test case was not resolved. Let me know if it is not really something this PR could be able to solve. I will submit it as a separate issue, accordingly. Thanks. |
@cagdastulek Have you enabled partial refetch? |
Yes, it didn't help either. |
For the people that were still having issues with this PR merged, I've opened up a followup PR that should take care of the remaining issues: #2493 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@steelbrain @hwillson
I think this code makes #556 situation. (Bug)
Let's assume using Query
component with network-only
policy. Query response is always will be cached. It means Object.keys(currentResult.data) !== 0
, right?
If then, fetchPolicy
is ignored. It will always consume cached result. In other words, if something is already cached, fetchPolicy is ignored
@steelbrain and others, I was thinking it might be nice if this edge case could be detected and the user could be alerted of what is going on without them having to figure it out on their own and find this PR. I think a short message in the console could be really helpful. Something like: An error occurred while trying to refetch the query XX from the cache. If you want this query to refetch in this instance please use the partialRefetch: true prop, or if you don't please explicitly pass a disablePartialRefetch: true. More info: #2003 (and a link to the docs) What do people think about that? IMO it's much better than getting the confusing no error, no data situation. |
A question related to this, when the query is being refetched, the loading flag is flipped to true for the main query, which shows a spinner in our case. Is there a recommended way of handling this? Thanks for all the work that went into this fix! |
Situation
When an object is mounted, and a mutation is executed that returns the same ID as the mounted object but has less fields,
loading
is returned asfalse
butdata
is an empty object as returned from this line inapollo-client::QueryManager
.An internal error is generated of course with the message template
Cannot find field $FIELDS on Object
but that's swallowed and never shown to the user in the code referenced above.A repro for this error can be found at stevehollaar/react-apollo-error-template@
mutate-bug
Possible fixes
There are multiple fixes that were evaluated for this, each with it's own downside
...fragment
way (which fills in the fields automatically) or specify a manual store updater.The last one seemed to be the most straight forward and simple solutions with no side effects so that's what I've done here.
This PR fixes apollographql/apollo-client#3267 #1314
Credits
Thanks @stevehollaar for his repro-case and constant support in this quest
Todo