-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
useQuery
data invalidated by useMutation
causing infinite loops (rerender)
#10261
Comments
In my case, using a more precise dependency is enough to fix the problem. useEffect(() => {
if (dataFetchUser?.fetchUser.id) {
createHouse({ variables: { ownerId: dataFetchUser.fetchUser.id })
}
},
[dataFetchUser?.fetchUser.id], // here
// instead of `[dataFetchUser]`
) However, I still think it's really hard to understand/spot the cause of the error and that the documentation or behavior could be improved. |
This to me is an indication that perhaps apollo is updating the cache, which triggers an update on your query. I'm not sure if this is default behavior or that you have a specific cache implementation that does this. Either way, this seems reasonable to me, and also that the query updates. The real problem here in my opinion is the use of The 'proper' way to do this is with a
|
Hey @FritsvanCampen, thanks for your comment. Indeed, it's a reasonnable behavior, but the mutation is returning the exact same object as the query, thus the incomprehension of losing the reference.
The I found that the Since, I'm entirely relaying on the state for the |
We live and learn 😄
The mutation is likely triggered by some user input somewhere, hopefully not too far away. I get the impression that rendering a component triggers the mutation, but something has to trigger the rendering of the component, right? See if you can trigger the mutation there. Using
This makes it very obvious were triggering a mutation during the render phase; the consensus is that this is not a good idea. 'Fixing' this might have a ripple effect on your code but I do think it's the right way to do it. In any case, I don't think this is an issue for Apollo. |
The component is rendered when the user visits/lands on the page. There's no user input up the stream.
I'm not sure I understand what you mean there. Is it an example of what you should not do? Because
We derived a bit from the initial issue, by discussing the use of |
You've got your user input right there 😄. Trigger the mutation on page load outside of the component.
I understand. That's a much narrower issue. I think that pleading for your expected behavior to be the default is not likely to be successful. The obvious way to get your behavior is to compare the data before deciding to emit an update. A compare is not cheap, and in most cases the data will have changed, why else did you refetch? I think you can implement a custom caching strategy that does what you want, so the option is available to you; but having this as a default is not likely to be accepted. |
Where should I put it? It's the first component that renders and needs the information. I'm not using SSR on this page.
I didn't refetch. It's the result of the
Yes, and I thank you for challenging it. Afterward, I still think it may profit the apollo client to detect an infinite loop caused by a lost data reference due to cache updates. I imagine the
|
You refetch it as part of your mutation result. You don't have fetch the whole result of a mutation. You can just leave out parts of the result you're not interested in. If you still want to pursue this in Apollo I would suggest you make a new ticket with the narrower revised case, something like: useQuery emits an update after refetch even if data doesn't change. |
The
data
reference returned byuseQuery
changes when auseMutation
returns the same type, even if it's the same resulting object.This behavior causes infinite loops when the mutation call depends on the query data.
Some details:
Fetch policy:
cache-first
(default)The
useQuery
doesn't refetch the data, it just invalidates the reference, making it impossible to correctly track changes throughuseEffect
dependencies.From what I understand, it's replaced by the updated
cache
from themutation
call.Intended outcome:
query.data
and themutation.data.nested.field
the data reference should be kept the same. Now, since it's complex objects, I understand it may be impossible to compare the results without a custom policy.useQuery
allowing to prevent this behavior. (I tried usinglazyQuery
orrefetch
without success).Actual outcome:
How to reproduce the issue:
given the following GQL schema
and the following react hook
Additional note:
Removing the
User
from themutation
result......prevents the
useQuery
data to lose its reference. That's the reason that makes me think that apollo is replacingdataFetchUser.fetchUser
withdataCreateHouse.createHouse.owner
, thus losing the reference.Versions
System:
OS: Linux 5.15 Ubuntu 20.04.5 LTS (Focal Fossa)
Binaries:
Node: 16.14.2 - /usr/local/bin/node
Yarn: 1.22.18 - /usr/local/bin/yarn
Browsers:
Chrome: 106.0.5249.91
npmPackages:
react: 18.2.0 => 18.2.0
react-dom: 18.2.0 => 18.2.0
typescript: 4.5.5 => 4.5.5
@apollo/client: 3.7.1 => 3.7.1
I don't think it's a duplicate of #6760 since they are discussing about the behavior of the fetch policy
cache-and-network
.Also I struggled to find the problem and I first encountered this now closed issue #9204
The text was updated successfully, but these errors were encountered: