Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

useQuery returns incorrect results when returning from the cache #3717

Open
tomitrescak opened this issue Nov 27, 2019 · 12 comments
Open

useQuery returns incorrect results when returning from the cache #3717

tomitrescak opened this issue Nov 27, 2019 · 12 comments

Comments

@tomitrescak
Copy link

tomitrescak commented Nov 27, 2019

I have a list control that uses useQuery to search for items.
For simplicity I write useQuery(QUERY, XXX), where XXX is a current parameter of the query.

Component calls useQuery in following order (as I type in the search bar):

useQuery(QUERY, '') // all good all records are returned
useQuery(QUERY, 'f') // records only with 'f' in the name are returned
useQuery(QUERY, '') //  ERROR: here I expect again ALL records, but only the 'f' record is shown 

How to reproduce the issue:

Reproduction code in the next post.

Here is a gif:

Nov-27-2019 22-37-02

Version

  System:
    OS: macOS 10.15.1
  Binaries:
    Node: 12.8.0 - /usr/local/bin/node
    Yarn: 1.19.1 - ~/.yarn/bin/yarn
    npm: 6.12.0 - /usr/local/bin/npm
  Browsers:
    Chrome: 78.0.3904.108
    Firefox: 70.0.1
    Safari: 13.0.3
  npmPackages:
    @apollo/client: ^3.0.0-beta.14 => 3.0.0-beta.14 
    @apollo/react-testing: 3 => 3.1.3 
  npmGlobalPackages:
    apollo-fetch: 0.7.0
    apollo: 2.21.0
@tomitrescak
Copy link
Author

OK, took some time, but I have a complete repro for you. Just run the code below and first type 'f', it will filter the dogs with 'f' in the name. Then delete 'f' and you'll see that nothing will happen as the query returns incorrect data.

Setup

npx create-react-app my-app --typescript
cd my-app
yarn add @apollo/client
yarn add @apollo/react-testing
yarn start

then, replace file App.ts with this file below:

import { MockedProvider } from "@apollo/react-testing";
import React from "react";
import gql from "graphql-tag";
import { useQuery } from "@apollo/client";

// Make sure the query is also exported -- not just the component
export const GET_DOG_QUERY = gql`
  query getDog($name: String) {
    dogs(name: $name) {
      id
      name
      breed
    }
  }
`;

export function Dog() {
  const [search, setSearch] = React.useState("");
  const { loading, error, data } = useQuery(GET_DOG_QUERY, {
    variables: { name: search }
  });

  return (
    <>
      <label>Search: </label>
      <input value={search} onChange={e => setSearch(e.currentTarget.value)} />
      {loading && <p>Loading...</p>}
      {error && <p>Error!: {JSON.stringify(error)}</p>}
      <ul>
        {!loading &&
          data.dogs.map((d: any) => (
            <li key={d.name}>
              {d.name} is a {d.breed}
            </li>
          ))}
      </ul>
    </>
  );
}
// The component AND the query need to be exported

const mocks = [
  {
    request: {
      query: GET_DOG_QUERY,
      variables: {
        name: ""
      }
    },
    result: {
      data: {
        dogs: [
          { id: "1", name: "Fido", breed: "bulldog" },
          { id: "2", name: "Bucky", breed: "pitbull" }
        ]
      }
    }
  },
  {
    request: {
      query: GET_DOG_QUERY,
      variables: {
        name: "b"
      }
    },
    result: {
      data: {
        dogs: [{ id: "2", name: "Bucky", breed: "pitbull" }]
      }
    }
  },
  {
    request: {
      query: GET_DOG_QUERY,
      variables: {
        name: "f"
      }
    },
    result: {
      data: {
        dogs: [{ id: "1", name: "Fido", breed: "bulldog" }]
      }
    }
  }
];

const App: React.FC = () => {
  return (
    <MockedProvider mocks={mocks} addTypename={false}>
      <Dog />
    </MockedProvider>
  );
};

export default App;

@zicodeng
Copy link

zicodeng commented Dec 8, 2019

I am facing the exact issue, did you end up finding a solution?

I have also reported it here: #3742

@tomitrescak
Copy link
Author

I am not sure why there is no response from the Apollo team but they must be swamped with preparing 3.0 launch. This is a serious bug IMHO :/

@zachasme
Copy link

zachasme commented Dec 9, 2019

As a temporary workaround you can use network-only fetchPolicy for queries that are affected by this issue.

@kapolos
Copy link

kapolos commented Jan 1, 2020

Still happening on ^3.0.0-beta.16

@FH-Hersey
Copy link

Any update on this? Use network-only for us is not an option

@zachasme
Copy link

According to apollo-client#5659 this was fixed in 3.0.0-beta.24

@bulutfatih
Copy link

For a temporary solution, you can try to set fetchPolicy: 'no-cache'

@m1m6
Copy link

m1m6 commented Jan 31, 2020

same issue here, even after migrating to last version or using fetchPolicy: 'no-cache'

@robertvorthman
Copy link

Found a workaround by switching to useLazyQuery. I put the search parameter in a useEffect dependency, then the useEffect will execute the query anytime the search parameter changes.

const [getSearchResults, { loading, error, data }] = useLazyQuery(GET_SEARCH_RESULTS, {
    variables: {
      search: mySearch
    }
  });

  useEffect(() => {
    getSearchResults();
  }, [mySearch]);

@defg
Copy link

defg commented Apr 29, 2020

I'm having the same problem when using a Subscription. When changing the query/variables by removing a field, the results don't change. The subscription/query doesn't even decide to fetch again. This is true even when no-cache is set. This fails on react-apollo 3.0.0 and up. The same code works on 2.5.8 and below.

I can provide sample code if needed, but I'm assuming I'm seeing the same bug as already mentioned.

Has anyone had any luck with fixes that would work with a Subscription?

@laurenthox
Copy link

Hi! I had the same problem, was getting the wrong results from cache, adding:
__typename @skip(if: true) on the query, fixed it.

this article helped: https://kamranicus.com/posts/2018-03-06-graphql-apollo-object-caching

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants