apollo-client: RefetchQueries after mutation not updating UI, yet network tab shows new data
Intended outcome:
I’m trying to authenticate a user and have it update my navbar (which uses the same query) to show different options whether the user is logged in or not.
Actual outcome:
Whats actually happening is, after refetching (during the login mutation), im getting new data from my query, and the network tab is showing it, store seems updated, however the component itself is still rendering stale data (outputted via console.log). Doing a hard refresh fixes the issue (since we get new data). How to reproduce the issue: I made a little demo video: https://drive.google.com/file/d/1Zmp1nwJBYnkuO0Cr2x4jUSnY61REkD8X/view
To explain the justification, i have a user query here that checks at a high level:
- Enter landing page (query returns undefined here makes sense)
- Enter login page, and login (cache updates with new data)
- console.log(this.props) to see our queries response, returns user is not authorized. After looking at apollo console data is in there (new) and the network tab that new data is in there. Refreshing the page shows relevant information however that query always rerenders the components involved with stale data.
const isLoggedInQuery = gql`
query isAuthenticated {
currentUser {
id
firstName
lastName
gender
location
password
email
permissions {
id
name
displayOrder
description
}
roles {
id
name
description
displayOrder
}
}
}
`;
export default graphql(isLoggedInQuery, {
name: "isLoggedInQuery"
})(Main);
If the user isn’t authed it returns null
In my login component i have it like this:
this.props.mutate({
variables: { token },
refetchQueries: [
{
query: gql`
query isAuthenticated {
currentUser {
id
firstName
lastName
gender
location
password
email
permissions {
id
name
displayOrder
description
}
roles {
id
name
description
displayOrder
}
}
}
`
}
]
});
Versions
“react-apollo”: “^2.1.4”,
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 55
- Comments: 129 (15 by maintainers)
Commits related to this issue
- fix: update network policy Two sets of changes: 1. Replace `forceFetch` usage with a network-only fetch policy (API change) 2. Set cache-and-network fetch policy for all queries that are refetched T... — committed to politics-rewired/Spoke by bchrobot 4 years ago
- fix: update network policy Two sets of changes: 1. Replace `forceFetch` usage with a network-only fetch policy (API change) 2. Set cache-and-network fetch policy for all queries that are refetched T... — committed to politics-rewired/Spoke by bchrobot 4 years ago
Nobody from from apollo team cares
On Tue, Sep 4, 2018, 8:38 PM sandorvasas notifications@github.com wrote:
This is a huge blocker bug for our app too.
Edit: it DOES seem to work if i use a function. So replacing
with
does update the UI for me properly with the previous variables with which getBookings had been called.
I’m using the graphql HOC btw.
@hwillson, it’s been two months and this issue has not been closed, if you really cares, you should check it out on your testing lab and verify it, If you cannot reproduce this, then close this issue so it wont be a clutter. i dare you to close this issue… 😃
@kkotwal94 i’m seeing this same issue even though there were not any errors with the initial query
Yeah I’m not seeing an error in my queries. Basically a mutation is run and I can verify via the chrome network tab that the updated data is arriving, however even with refetchQueries set, the component is still displaying stale data.
This fixed the issue for me on the latest packages and react. refetchQuery MUST match the variables from when the query was last ran.
I could not get the UI to refresh after a successful mutation-and-then-query using the
<Mutation refetchQueries={['queryName']} />
render prop pattern. My<Query />
component was high up in the app structure, with the<Mutation />
as a deeply nested child component.I fixed the issue by following the instructions above. So that included adding the
fetchPolicy
prop to the<Query />
AND changing therefetchQueries
prop to a function returning an array instead of just an array.refetchQueries={['queryName']}
becamerefetchQueries={() => ['queryName']}
Hope this helps! Here are my apollo versions:
├─ apollo-boost@0.1.27 ├─ apollo-cache-inmemory@1.4.2 ├─ apollo-cache@1.1.25 ├─ apollo-client@2.4.12 ├─ apollo-link-context@1.0.12 ├─ apollo-link-dedup@1.0.13 ├─ apollo-link-error@1.1.5 ├─ apollo-link-http-common@0.2.8 ├─ apollo-link-http@1.5.9 ├─ apollo-link-state@0.4.2 ├─ apollo-link@1.2.6 ├─ apollo-utilities@1.1.2 └─ react-apollo@2.4.1
EDIT: It turns out the core issue I was facing was not apollo-related at all 🤦♂️. I wasn’t seeing UI updates because I was copying data to React component
state
rather than reading it fromprops
in a component that sits between the<Query />
and the<Mutation />
, meaning the updated query response only made it through the tree down to the offending component, which did not update itsstate
. Once I realized this, I was able to implementrefetchQueries
as follows:<Mutation refetchQueries={['queryName']} />
(it also still works for me by passing a function that returns an array)And then I removed the
fetchPolicy
prop from my<Query />
altogether, which means I am now using the defaultfetchPolicy
,cache-first
.Hopefully @hwillson can take a look at this, once 2.5 beta is released. To me, this is either something very silly we’re missing, or a big red no-go for Apollo Client, especially when the tutorial that’s supposed to teach every one how great Apollo is, doesn’t work.
Scott
I have been having the same issue. I have spent 4 days debugging this but to no avail. The Network shows correct data, meaning the mutation is running and the refetch query is running and the correct data is coming in. However the UI is not rerendering to reflect it. I am now considering completely dumping Apollo 3.0 which has gone from Beta to official and making GraphQL queries with simply Axios or Fetch. Such a large buggy unwieldy bunch of functionality is like a prior day dinasaur reincarnated. Apollo says we need caching and so forth, yes but before that our more important need is that simple things like RefetchQueries work out of the box. Currently this thread shows, even after the release of Apollo3.0 official, they dont work. A huge amount of time is wasted on finagling a feature that should just work to work. And if it still doesnt work, the whole library has to be dumped. God knows by this thread so many people have tried to get it to work for so long. This after noon I am going to implement simple access to Graphql API using fetch or axios and bypass this whole mess.
@iamrommel The Apollo team is small (we’re hiring!). Anything the community can do to help reduce the amount of time issue triaging / bug fixing takes (like creating reproductions) goes a long way towards helping get issues resolved faster. If someone in this issue thread is able to help out, that would be awesome.
Same for me. I have a complex query (custom sorting based on several options) so updating the store manually is not an option, unfortunately. My mutation is successful, but when I run
refetchQueries
(or this.props.data.refetch() explicitly in theupdate
function), my UI stays stale. If I look in the network tab I can see that the refetch actually happened and the dataset plus my new item created from my mutation was fetched.Edit: Looks like I can get it to update the UI with an explicit call to
refetch
in theupdate
function if I have the propertyfetchPolicy
set tocache-and-network
on my list. HoweverrefetchQueries
still is not working as mentioned.neither of the suggestions mentioned in https://github.com/apollographql/react-apollo/issues/2070 (changing
fetchPolicy
or passing variables to Query i.e{v: Math.random()}
) helped with the issue.Oh wow this did the trick. The docs technically do have it correct, but some practical examples would be extremely helpful.
Thanks all - looks like this issue has been resolved.
Is there any official word on this issue from the apollo team?
We were rendering the mutation component with refetchQueries like so:
For us the issue was that the query had to be exactly the same in the refetch as when the component was first rendered. INCLUDING variables! Our variables were changing slightly between when the query was first run and on the refetch and was causing the re-render not to happen. This is definitely not the fix or a lot of the examples I’m seeing above, but hopefully it helps some people out.
This solves my problem completely.
was able to solve by following this: https://github.com/apollographql/react-apollo/issues/2070, for anyone else who stumbles on this issue. My initial result of the query was always a error, hence refetching didnt set it back into its loading state unless you set the query you were refetching to cache-and-network.
I’ve tried following solution to solve this, but all are failed
fetchPolicy="cache-and-network"
errorPolicy="ignore"
awaitRefetchQueries={true}
variables={{ v: Math.random() }}
refetchQueries: [ 'getBookings' ]
torefetchQueries: () => [ 'getBookings' ]
versions
Guys,
I had the exact same issue. But as @kkotwal94 mentioned if you add
fetchPolicy="cache-and-network"
it works perfectly.I set my Mutation:
Component A
I set my Query:
Component B
The component A redirects to Component B with the updated values.
Hope it helps.
Shall we assume the Apollo team have completely forgotten about this? I appreciate the effort but there hasn’t been an update for months and this is one of many important features within apollo-client…Due to this and the network-policy issues we might have to consider switching to an alternative library instead
Thank you so much! I spent the last 4 hours debugging this.
The majority of this thread is people not understanding how Apollo works with its cache. There IS no bug here.
If you use any form of query with a
fetchPolicy
that doesn’t cache (likeno-cache
), thenrefetchQueries
in a mutation won’t do anything. Why? There is no cache to update from the mutation. If you want it to reload, you need to remount the component. (Yes,refetchQueries
is named poorly IMO).What SHOULD you do? Use a query with a
fetchPolicy
that has a cache option. If you need “always network” data, but still want this to work then usenetwork-only
(which still caches) as thefetchPolicy
. It will keep a cache so it can see mutations, but it will always query the server on mount/render/cache-bust (the cache bust is what therefetchQueries
is doing).Note: you can use any
fetchPolicy
with a cache to cause re-renders on mutations (list offetchPolicy
options here)The other thing people seem to be missing is that QUERIES WITH VARIABLES ARE KEYED IN THE CACHE WITH THOSE VARIABLES. So if the variables change by the time you perform your mutation, then it won’t know which key in the cache to update. Thus no re-render. If you want to use queries with changing variables, you need to customize your cache normalization behavior. See https://www.apollographql.com/docs/react/caching/cache-configuration/#data-normalization.
Read that again: if the variables change, the query won’t refresh. This is because the cache considers those different queries, as it should.
I don’t work for Apollo, but someone that does should come here, clarify what I said with more details/info, then close this issue. Also, they should update the documentation to be more clear about this subject. I get the frustration everyone has here. I felt it too until I saw the light.
Checklist when refetch queries is not working:
refetchQuery
exactly the same?fetchPolicy
in the query set to'network-only'
?nextFetchPolicy
in the query set to'network-only'
?Now, once your application is working correctly, you can start to think about reducing network requests.
ok, 2020 here is my work around guys, instead of using
lets call fetchMore since fetchMore is working correctly, so we can pass the initial default variables, yeah sounds funny.
thanks 😄
Here’s what I did
refetch
when you calluseQuery
set
fetchPolicy
tocache-and-network
in thisuseQuery
invocation`call
refetch(...)
in the your mutation’sonCompleted
callback (usinguseMutation
)I’ve struggled to get updates working tbh. I had to move on and just settle for refetch even though I hate the fact that it does 2 queries for a single mutation 😦
To sum it up, what works here is to first define appropriate cache policies:
Second: make sure the
variables
are exactly the same as in the initial query.@julian-sf As I wrote on Feb 29th, 2019: We had the same problem (btw also with network-only), but the problem occurred only in IE. In Chrome everything was fine. So two browsers give two different outcomes and you want to tell me that it’s not a bug but a feature?
I think the people in this issue are very frustrated when they find a bug that doesn’t get fixed or even noticed and then someone tells them, they are just too stupid for the profession they do. Obviously something here went wrong, but it seems hard to reproduce.
For the people wondering how we solved this particular issue with Apollo: We don’t use it anymore. Easy as that 😉
@optimuspaul There is a refetch method supplied by Query components:
https://www.apollographql.com/docs/react/essentials/queries.html#refetching
refetchQueries are, as I understand it, basically meant to help you by not forcing you to pass that function around your app like a strand of spaghetti.
@dbertella - What if the mutation is called in a child component? The resolver is returning the new data for the parent component, but the UI isn’t getting updated. See:
https://github.com/apollographql/fullstack-tutorial/blob/7948b85d747300fd4d1596b6173b9ee783431c75/final/client/src/containers/action-button.js#L11
https://github.com/apollographql/fullstack-tutorial/blob/7948b85d747300fd4d1596b6173b9ee783431c75/final/client/src/resolvers.js#L27
of the full-stack tutorial as an example of what I mean. If you run the app and server in the tutorial, add a space flight/ mission to your shopping cart, then go to the cart and remove it, the mission and the remove button stay instead of the mission being removed from the cart. (in the background, the mission is removed from the cart).
Scott
Hey guys. It seems that I’ve found the trick to reproduce the issue. Here is my code:
The first time when entering this page and if not signed in, the query will fail due to 401. After that If I signed in and add a vehicle via a mutation like this:
When user trigger the mutation the expected behavior is in the VehiclesQuery the list will rerender due to the refetchQueries in mutation. However nothing happened.
The magic thing happens when I set the default state of the apollo-link-state into this:
instead of this:
It seems that if the first time the query is not successfully fired and no default state in link-state is provided for this query, all the refetchQueries and writeCache that associated with it will not work as expected.
Hope it will be helpful.
I was running into a similar issue - documenting my fix here although it looks like this wouldn’t fix it for the original poster.
TL;DR:
Switching from
to
fixed the issue for me. See this issue comment for more details.
Longer description of issue to hopefully help someone fix this:
In my case, we had a list query (
groups
) that took no variables. When we deleted an item from the list, we would refetch the query instead of updating the cache directly:Worked with no issues. We also added an option to “undo” the group deletion. We’d store the group info, and on undo, would just create a new group with all the old info:
That worked fine too. The old group got recreated (with all the same data except a new
id
field), UI updated perfectly.The issue was when we tried to delete that restored group - exact same code as above should have fired, and it did. A network request to delete the group was successful, and another followup to refetch the
groups
query returned the correct data - but the cache and UI did not update.If we deleted a group, undid the delete, navigated away and came back (i.e. unmounted and remounted the observable query in the restored group), we could successfully delete the restored group and the UI would update. This definitely feels like an Apollo bug related to the
string
option of therefetchQueries
array, given that switching to the object syntax fixes the issue.The documentation is also lacking around this point. It fails to mention that a named query string will only refetch if it exists in mounted, observable queries, whereas passing an object with a query document will always run the query.
This also fixed a separate, unrelated issue where we ran the undo and related
refetchQueries
asynchronously, after navigating away from the original observable query. Again, it’s not well-documented.I have to add that none of the solutions mentioned here worked - fetchPolicy, variables ordering etc
I ended up moving the logic from
onCompleted
to auseEffect
withdata
as dependency, which is working as expected. I got the solution from hereThanks for the response @Ruslan @Johnny. However, please note the following points:
So the refetch is working at the network request level, but it is most strangely not updating the UI.
I have been stuck on this for many days. I am at a loss. Dont know what to do further.
Best regards, arjuna
On Wed, Jul 22, 2020 at 8:57 AM Johnny Bell notifications@github.com wrote:
This also took me a long time to figure out, but as long as you call it with the same variables then it will work. It can be super frustrating but I don’t think thats a reason to ditch apollo-client, it has a lot of other amazing features.
And when it comes to matching the variables, it appears that the types also matter. I was passing an int (
42
) for my refetch query while the initial query has a string ("42"
) and that was preventing it from working.I am having same issue. As workaround I am manually changing the state of the component to force the component to re-render on refetch
Solved my issue. My data connection was timing out, always leaving me with an empty array of
savedItems
.cache-first
can’t work because it doesn’t know what the new cache is,cache-and-network
can’t work because the network call on the end returning[]
(timeout default) was wiping out the good data.TL;DR use
update
.refetchQueries
is only as reliable as your data connection, probably why it’s not recommended for in place UI updates.@madisonbullard that helps! My issue was that I was not passing the variables into the refetchQueries array object, your syntax helped me find that.
refetchQueries={() => [{ query: YOUR_QUERY, variables: { whatever } }]}
I think Apollo could in general put more emphasis on the fact that whenever you call a query, whether through refetch or through cache, the variables need to be re-specified.
Hi all,
I think I figured out how the
refetchQueries
works with HOC. As you pass down in the variables that need to be assigned to your components, you need to pass also thegql
that contains your queries that you want to be refetched.(yes it can contain many queries. They are distinguished with their names:
BUT this is not enough to trigger a refetch. You know that within your component you need to
mutate
the variables that you passed down from the HOC right? OK, then you need ALSO to specify, with their names which queries within thegql
you want to be refetched.So, in your component, you need to specify it like below:
Btw, in my case, it works independent of the
fetchPolicy
.I hope it will help some of you guys.
Cheers!
@hutber I have had some success by setting partialRefetch={true} on the <Query /> component. Maybe worth a shot.
It returns the whole cart object, either with the new mission added, or the mission deleted. The logic is based off of ids, so the ids are there. It’s just not one id, but possibly none or more than one.
I guess the question should be, if the Apollo cache is updated, will the UI displaying that data be updated automatically too? Or does something else need to be triggered? I’m far from an Apollo expert and even farther from a Apollo React expert. 😁
Scott
@iamrommel We care! If someone here can provide a small, runnable reproduction that clearly demonstrates this issue, that would greatly help with getting this resolved.
On my side, variables are matching 100% but still, UI is not updating! 😐
OK,
refetchQueries
fixed. Below is a sample of what I updated in my case, and steps that could help you identify what you need to update in your particular case.Troubleshooting steps for your situation:
Make sure you provide the absolute same variables both to the original and to the refetch query as outlined in other posts above.
If (1) did not solve it, then you need to reveal what inconsistency you may have between your variables and how your data is stored in Apollo’s cache, because Apollo converts your variables into a JSON string and makes it a part of the key at which your data is stored in its cache:
A. Familiarize yourself with Apollo’s Making all other cache updates, specifically the
update
method.B. Make sure to include your original variables in the ‘update’ method in every place you are using the original query used to get data. This stackoverflow answer was helpful.
C. Try mutating your data while using the
update
method. In my case it immediately threw an error, which revealed the solution:Notice the data structure difference between these 2 lines:
As soon as I eliminated that difference in the original variables, the
refetchQueries
began to update the UI as expected.I’m in the process of safely migrating all of our render prop components to Apollo hooks, however once that’s done I will definitely upgrade to 3, grazie 😃
I am not sure that is the only issue. I am using
network-only
for one of my queries, and I see it fire in the network inspector (as in the original post) but the page doesn’t (always) re-render.In one case, I found that adding a
useState(false)
and flipping it after awaiting the refetch does re-render consistently, which smells very much like a React context state propagation bug.This is what I just discovered last week to. I had to change my
fetchPolicy
tonetwork-only
to make it work.I go with that @JustDoItSascha resolution, i turned away from using apollo because there are several issues that are not getting fixed which are reported for a very long time. I dont want to specify it one by one here as nobody listens. What happens is not a “issue tab on github” but rather “ranting tab” just like what i did. Hahaha
On Sat, Feb 15, 2020, 12:26 AM JustDoItSascha, notifications@github.com wrote:
In regarding to the refresh issue. I have the same trouble but with Angular 5 & 6 using Apollo Client 2.3. I think that is a sync issue.
No matter how do you write the refresh query, this works nice, but the mutation arrives first & the refresh milliseconds later without possibility to catch it: there is no an observable, or promise, of the refresh query to sync with it.
I resolve this issue with a separate query, changing the
fetchPolicy
tonetwork-only
. Its work like a charm.Why isn’t there just a reload method that we can call or trigger on the Query objects? Why all the complexity?
and the query thats being refetched has this option?