Skip to content
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

RefetchQueries after mutation not updating UI, yet network tab shows new data #3633

Closed
kkotwal94 opened this issue Jun 29, 2018 · 129 comments
Closed

Comments

@kkotwal94
Copy link

kkotwal94 commented Jun 29, 2018

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:

  1. Enter landing page (query returns undefined here makes sense)
  2. Enter login page, and login (cache updates with new data)
  3. 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",

@ghost ghost added blocking labels Jun 29, 2018
@kkotwal94
Copy link
Author

was able to solve by following this:
apollographql/react-apollo#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.

@stephenhandley
Copy link

@kkotwal94 i'm seeing this same issue even though there were not any errors with the initial query

@kkotwal94
Copy link
Author

@stephenhandley maybe i could post some code to help with this, i don't know if it'll solve your issue.
Maybe you can post your code too so we can see whats up.

Initally, this was a apollo error in the query if I wasn't logged in (because, im not logged in 👍 ), so refetching didn't work. Look at the export at the bottom and I had to do that.

The query name isAuthenticated gets refetched from my login component rerendering all my components using that same query.

Header.jsx

import React, { Component } from "react";
import { Link, withRouter } from "react-router-dom";
import gql from "graphql-tag";
import { graphql, compose } from "react-apollo";
import { withStyles } from "@material-ui/core/styles";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import Button from "@material-ui/core/Button";
import headerLinksStyle from "./HeaderLinksStyle";
import { Dashboard, LockOpen, GetApp, Info } from "@material-ui/icons";

const isLoggedInQuery = gql`
  query isLoggedInQuery {
    token @client
  }
`;

const loggedInMutation = gql`
  mutation authToken($token: String!) {
    assignAuthToken(token: $token) @client {
      token
    }
  }
`;

const userQuery = gql`
  query isAuthenticated {
    currentUser {
      id
      firstName
      lastName
      gender
      location
      password
      email
      permissions {
        id
        name
        displayOrder
        description
      }
      roles {
        id
        name
        description
        displayOrder
      }
    }
  }
`;

class HeaderLinks extends Component {
  logout = () => {
    localStorage.removeItem("auth_token");
    this.props.mutate({
      variables: { token: null }
    });
    this.props.history.push(`/`);
  };

  render() {
    const { classes } = this.props;
    const { token } = this.props.data;
    const isLoggedIn = token;
    console.log(this.props);
    return (
      <List className={classes.list}>
        {isLoggedIn && (
          <ListItem className={classes.listItem}>
            <Link to="/dashboard" style={{ color: "inherit" }}>
              <Button color="inherit" className={classes.navLink}>
                <Dashboard className={classes.icon} />Dashboard
              </Button>
            </Link>
          </ListItem>
        )}
        {!isLoggedIn && (
          <ListItem className={classes.listItem}>
            <Link to="/login" style={{ color: "inherit" }}>
              <Button color="inherit" className={classes.navLink}>
                <LockOpen className={classes.icon} />Login
              </Button>
            </Link>
          </ListItem>
        )}
        {!isLoggedIn && (
          <ListItem className={classes.listItem}>
            <Link to="/signup" style={{ color: "inherit" }}>
              <Button color="inherit" className={classes.navLink}>
                <GetApp className={classes.icon} />Sign up
              </Button>
            </Link>
          </ListItem>
        )}
        <ListItem className={classes.listItem}>
          <Link to="/about" style={{ color: "inherit" }}>
            <Button color="inherit" className={classes.navLink}>
              <Info className={classes.icon} />About
            </Button>
          </Link>
        </ListItem>
        {isLoggedIn && (
          <ListItem className={classes.listItem}>
            <Button
              color="inherit"
              className={classes.navLink}
              onClick={event => {
                this.logout();
              }}
            >
              <LockOpen className={classes.icon} />Logout
            </Button>
          </ListItem>
        )}
      </List>
    );
  }
}

export default compose(
  graphql(isLoggedInQuery),
  graphql(loggedInMutation),
  graphql(userQuery, {
    name: "user",
    options: { fetchPolicy: "cache-and-network" }
  }),
  withStyles(headerLinksStyle),
  withRouter
)(HeaderLinks);

Login.jsx:

const LOGIN = gql`
  mutation login($email: String!, $password: String!) {
    login(email: $email, password: $password) {
      token
      user {
        email
        firstName
        lastName
        location
        pictureUrl
        websiteUrl
        roles {
          id
          name
          description
          displayOrder
        }
        permissions {
          id
          name
          description
          displayOrder
        }
      }
    }
  }
`;

  login = (event, loginMutation) => {
    const { email, password } = this.state;
    console.log(this.props);
    loginMutation({ variables: { email, password } }).then(({ data }) => {
      const { token } = data.login;
      this.saveUserToken(token);
      this.props
        .mutate({
          variables: { token },
          refetchQueries: () => ["isAuthenticated"]
        })
        .then(data => {
          this.props.history.push(`/`);
        });
    });
  };

I omitted a lot from the second file, but i think that was all that was needed to be shown (let me know if you want to see the whole file).

@arvinsim
Copy link

I am also getting this same error. The solution suggested by @kkotwal94 did not work for me.

@kkotwal94
Copy link
Author

can you be a bit more specific, post some code maybe, the exact scenario, so we can disect it, maybe find the true root of the error?

@arvinsim
Copy link

@kkotwal94 Following the link your posted, it seems that it was problem in the react-apollo package. Scrolling down, it seem to be fixed but not yet released.

As for my issue, I verified that the incoming GQL data was updated. It's just the component that was not updating.

@kkotwal94
Copy link
Author

Im guessing this component is trying to fetch data? (So a query?) in my case it works for me so im trying to figure out the difference. If it was a mutation thats updating data then are you updating the cache (if you are manipulating the cache) or are you doing a refetch?

@stephenhandley
Copy link

stephenhandley commented Jul 19, 2018

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.

@arvinsim
Copy link

@kkotwal94 I am not doing query. I am doing a mutation and have the same problem as @stephenhandley.

@kkotwal94
Copy link
Author

and the query thats being refetched has this option?

graphql(userQuery, {
    name: "user",
    options: { fetchPolicy: "cache-and-network" }
  }),

@stephenhandley
Copy link

stephenhandley commented Jul 20, 2018

neither of the suggestions mentioned in apollographql/react-apollo#2070 (changing fetchPolicy or passing variables to Query i.e {v: Math.random()}) helped with the issue.

@kkotwal94
Copy link
Author

🤷‍♂️ Maybe we can compare versions and setup?

@stephenhandley
Copy link

here's relevant apollo/react libs I'm using

"apollo-boost": "0.1.5",
"graphql": "0.13.2",
"graphql-tag": "2.9.2",
"react": "16.3.2",
"react-apollo": "2.1.3",
"react-dom": "16.3.2"

@stephenhandley
Copy link

stephenhandley commented Jul 20, 2018

For what its worth I think enough people are seeing this issue that's there's something up with how they're updating the cache.
#3573

This appears to be related as well
#3169

Would be awesome if an ApolloClient maintainer could weigh in on this...

@Forfold
Copy link

Forfold commented Jul 25, 2018

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 the update 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 the update function if I have the property fetchPolicy set to cache-and-network on my list. However refetchQueries still is not working as mentioned.

@hwillson hwillson removed the blocking label Jul 27, 2018
@JeffML
Copy link

JeffML commented Aug 9, 2018

I had a simple, client side query. When i modified the data model to no longer update an @client property, I got no results back from the query. I was not using a schema for the client properties. When i removed that property from the query, all my results came back.

@iamrommel
Copy link

@hwillson , i think it is realted to apollographql/react-apollo#2070

@BipinBhandari
Copy link

Any update on this issue? This is breaking my app right now. This issue isn't fixed in 2.1.11 too

@cigrainger
Copy link

I have the same problem as @Auchindoun. An explicit refetch works but refetchQueries doesn't.

@sandorvasas
Copy link

sandorvasas commented Sep 4, 2018

This is a huge blocker bug for our app too.

Edit: it DOES seem to work if i use a function. So replacing

refetchQueries: [ 'getBookings' ]

with

refetchQueries: () => [ 'getBookings' ]

does update the UI for me properly with the previous variables with which getBookings had been called.

I'm using the graphql HOC btw.

@iamrommel
Copy link

iamrommel commented Sep 4, 2018 via email

@hwillson
Copy link
Member

hwillson commented Sep 4, 2018

@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.

@iamrommel
Copy link

@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.. :)

@julian-sf
Copy link

@julian-sf

If you use any form of query with a fetchPolicy that doesn't cache (like no-cache), then refetchQueries in a mutation won't do anything.
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 use network-only as the fetchPolicy.

Don't those two statements contradict each other? Or does network-only still use a cache? If so that label is misleading.

Oh, their documentation is super misleading. But their documentation DOES state that network-only calls the cache, although it stupidly says it in the no-cache policy description:

https://www.apollographql.com/docs/react/api/react-apollo/#optionsfetchpolicy:

no-cache: This fetch policy will never return your initial data from the cache. Instead it will always make a request using your network interface to the server. Unlike the network-only policy, it also will not write any data to the cache after the query completes.

@julian-sf
Copy link

julian-sf commented May 12, 2020

#3633 (comment)

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 fixed the issue for me on the latest packages and react. refetchQuery MUST match the variables from when the query was last ran.

I mean that's what I said here, #3633 (comment):

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.

#3633 (comment)

@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 ;-)

Oh, Apollo has bugs with IE for sure.

To your other point, I never claimed anyone was stupid. I tried to simply explain the inner working of the complex caching logic that Apollo uses. Nothing I said in my comment was incorrect. People are getting angry because I'm simply explaining the system to them. I didn't write the system, I'm just explaining that this is the INTENDED behavior from the Apollo client. The correctness of their intentions is up for debate, but the facts I stated in my comment are not.

Facts:

  • refetchQueries only updates fetches with a cached network policy
  • it will ONLY update calls that have the SAME VARIABLES (as that's how they are keyed in the cache)
  • all of this is intended behavior for the Apollo client.

People are excited about this comment here: #3633 (comment). But it's quite literally the concepts I previously explained.

@ruslanvs
Copy link

ruslanvs commented May 13, 2020

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.

// This change helped in my case. Please use the below steps to identify what you
// need to change in your case.
const variables = {
  first,
  - sortBy: [{ key, dir }], // removed
  + sortBy: { key, dir }, // added
};

Troubleshooting steps for your situation:

  1. Make sure you provide the absolute same variables both to the original and to the refetch query as outlined in other posts above.

  2. 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:

Invariant Violation: Can't find field books({"first":10,"sortBy":[{"dir":"ASC","key":"NAME"}]}) on object {
  ... // Other data
  "books({\"first\":10,\"sortBy\":{\"dir\":\"ASC\",\"key\":\"NAME\"}})": {
    "type": "id",
    "generated": true,
    "id": "$ROOT_QUERY.books({\"first\":10,\"sortBy\":{\"dir\":\"ASC\",\"key\":\"NAME\"}})",
    "typename": "BookConnection"
  },
  ... // Other data
}.

Notice the data structure difference between these 2 lines:

"books({\"first\":10,\"sortBy\":{\"dir\":\"ASC\",\"key\":\"NAME\"}})"
books({"first":10,"sortBy":[{"dir":"ASC","key":"NAME"}]}) // Array with an object

As soon as I eliminated that difference in the original variables, the refetchQueries began to update the UI as expected.

@brahmaforces
Copy link

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.

@ruslanvs
Copy link

I have been having the same issue. I have spent 4 days debugging this but to no avail...

Can see your frustration. I could recommend trying a fix per my post above. In particular, the part that helps you reveal a possible miss-match between your variables and the keys in the cache.

@johnnyxbell
Copy link

I have been having the same issue. I have spent 4 days debugging this but to no avail....

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.

@brahmaforces
Copy link

brahmaforces commented Jul 22, 2020 via email

@ruslanvs
Copy link

ruslanvs commented Jul 22, 2020

@brahmaforces I think the issue is clear now. In my past experience with Apollo Client delete mutations indeed could not (and were not meant to) be reconciled in cache declaratively. If you wanted the UI to update without refetching data on a delete mutation, you had to update the cache imperatively, using the writeQuery method.

I'm not aware of the very latest details there and you may need to make sure you are using the right docs for the version of the client you are using, but this link may be helpful as a starting point: https://www.apollographql.com/docs/react/caching/cache-interaction/

Addition: if you are willing to refetch the list on mutation like you described above, an alternative quick fix could be to abandon the use of UI cache for this query by setting fetchPolicy: 'network-only' on your original query.

@sabit990928
Copy link

sabit990928 commented Aug 6, 2020

Look like I have a specific case. For some clearence, I have student and teacher. Student should send some answer, then teacher should view list of answers. I fetch the time when student send answer and refetchQuery calls in case when there is already done one request, it works fine. But the problem when I completed mutation, then query shows old data. I'm using chromnium. It looks like that fetching a little old data. It works only if you run it on the first time. But if it run and has a cache, it means that you have no data in component and if it calls, it will return old data

@brahmaforces
Copy link

brahmaforces commented Aug 7, 2020 via email

@yeomann
Copy link

yeomann commented Aug 7, 2020

using AC3 and refetch() didn't tirgger update for me. waooo sad ..... :/

@yeomann
Copy link

yeomann commented Aug 7, 2020

ok, 2020 here is my work around guys, instead of using

refetch()
OR
refetch(DEFAULT_VARIABLES)

lets call fetchMore since fetchMore is working correctly, so we can pass the initial default variables, yeah sounds funny.

fetchMore({
      variables: DEFAULT_VARIABLES
})

thanks 😄

@jordiup
Copy link

jordiup commented Oct 21, 2020

The thing that fixed it for me was changing the fetchPolicy on the awaiting component. So that it didn't default to using the cache

const { data, error } = useGetProductsQuery({
fetchPolicy: 'cache-and-network'
});

@agileapplications
Copy link

To sum it up, what works here is to first define appropriate cache policies:

{ fetchPolicy: "cache-and-network", nextFetchPolicy: "cache-first" }

Second: make sure the variables are exactly the same as in the initial query.

@joshuarobs
Copy link

joshuarobs commented Apr 27, 2021

I had this problem.

I solved it by doing what @agileapplications did, but I didn't set a netFetchPolicy at all. Also, the second query (aka refetch query in the mutation) doesn't need to have a fetchPolicy set, because you can't have any there.

However, my issue was caused because I'm using apollo-client on the server, to query my Hasura db. It seemed that doing the above wasn't enough, so I had to set certain queries as fetchPolicy: 'network-only' on the server's apollo-client too. That way the server could query the latest data, and thus, would serve it to the client. Not sure if it'll work for my other queries since I haven't tried it yet, but it worked for 1 of them.

Now I don't have to worry about making a change, constantly repeatedly refreshing the page and seeing no changes in the UI anymore.

Edit 1: (May 8, 2021)
Got this same problem again. My previous solution ended up working again for other functions, more than just the 1 I initially tried. It also worked for this problem again where some data/part of the UI wouldn't update and would be stubborn, so I set the fetch policy on the backend again for that function to network-only.

@hwillson
Copy link
Member

Thanks all - looks like this issue has been resolved.

@ManalLiaquat
Copy link

We were rendering the mutation component with refetchQueries like so:

refetchQueries={[
    {
        query: QUERY,
        variables: { location, tags }
    }
]}

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 fixed the issue for me on the latest packages and react. refetchQuery MUST match the variables from when the query was last ran.

On my side, variables are matching 100% but still, UI is not updating! 😐

@revsend
Copy link

revsend commented Jul 1, 2021

Checklist when refetch queries is not working:

  • Are the variables in refetchQuery exactly the same?
  • Is the fetchPolicy in the query set to 'network-only' ?
  • is the nextFetchPolicy in the query set to 'network-only'?
const { data } = useQuery(TODOS, { 
  variables: { first: 10 }, 
  fetchPolicy: 'network-only', // Important!! Apollo will default use cache first
  nextFetchPolicy: 'network-only' // Important!! 
})
const [updateTodo] = useMutation(UPDATE_TODO, { 
  variables: { id: 1, title: 'Foo' }, 
  // The variables NEEDS to match EXACTLY! Double check!
  refetchQueries: [{ query: TODO, variables: { first: 10 } }]
})

Now, once your application is working correctly, you can start to think about reducing network requests.

@palerdot
Copy link

palerdot commented Jul 27, 2021

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 a useEffect with data as dependency, which is working as expected. I got the solution from here

@stephenwoosley
Copy link

@palerdot your solution worked for me. Thanks for the link!

@osdiab
Copy link

osdiab commented Jul 17, 2022

FYI another simple thing you can do that worked for me—I didn't want to mess around with how we were refetching since it's pretty complex already, but while the apollo hook doesn't return a different object, it does cause a rerender where its called. And additionally, the query's loading state does change (EDIT: reliably if you enable the notifyOnNetworkStatusChange parameter). So a simple option is to just either A) pass the loading state as a prop to whatever you want to have a rerender triggered on (would render twice per refetch), or B) keep track of a loadCount that you can pass whenever refetches complete to trigger the rerender for whatever is failing to update (which would only change once per refetch). For example:

function ParentComponent() {
  const { data, refetch, loading } = useQuery(MY_QUERY, { notifyOnNetworkStatusChange: true, /* whatever */ });
  const [loadCount, setLoadCount] = useState(0);
  useEffect(() => {
    if (loading === false) {
      setLoadCount(value => value + 1);
    }
  }, [loading]);

  // this will rerender every time a refetch happens
  return <MyComponent loadCount={loadCount} />;
}
const MyComponent = memo(function MyComponentImplementation(props) {
  return <div>Whatever</div>; // not actually using loadCount, but it does make it rerender.
});

@brahmaforces
Copy link

brahmaforces commented Jul 18, 2022 via email

@osdiab
Copy link

osdiab commented Jul 18, 2022

@brahmaforces that depends on your use case, for ours we really did want to refetch and do a round trip to the server. regardless just a workaround that might be helpful to others.

@RemyMachado
Copy link

Thanks all - looks like this issue has been resolved.

How has it been resolved? What's the solution? There's a hundred messages and after reading them all I don't see any solution.

@adamperrry
Copy link

adamperrry commented Feb 20, 2023

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

 refetchQueries: ['namedQuery']

to

 refetchQueries: [{ query: NAMED_QUERY_DOCUMENT }]

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:

const [deleteGroup] = useDeleteGroupMutation({
  variables: { id: group.id },
  refetchQueries: ['groups'],
  awaitRefetchQueries: true,
});

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:

const [createSiteGroup] = useCreateSiteGroupMutation({
  refetchQueries: ['groups'],
  awaitRefetchQueries: true,
});

// Actually deleting group
deleteSiteGroup().then(({ data: deleteData }) => {
  const deletedGroup = deleteData!.deleteGroup;

  const undo = async () => (
    await createGroup({
      variables: {
        name: deletedGroup?.name,
      },
    })
  );

// Call the undo somewhere conditionally, like in a toast notification
  await undo();
})

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 the refetchQueries 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.

@lnfernandobr
Copy link

But what to do when the query has some arguments? { query: QUERY, variables: {...} } You'll need to provide the same object that you used to fetch data before. This not makes sense...

Using a string means that you shouldn't have to provide the same object as Apollo should automatically fetch the query with the current query variables.

@github-actions
Copy link
Contributor

github-actions bot commented Apr 2, 2023

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
For general questions, we recommend using StackOverflow or our discord server.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 2, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests