react-apollo icon indicating copy to clipboard operation
react-apollo copied to clipboard

useQuery returns incorrect results when returning from the cache

Open tomitrescak opened this issue 4 years ago • 12 comments

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 avatar Nov 27 '19 10:11 tomitrescak

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;

tomitrescak avatar Nov 27 '19 11:11 tomitrescak

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

I have also reported it here: https://github.com/apollographql/react-apollo/issues/3742

zicodeng avatar Dec 08 '19 21:12 zicodeng

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 :/

tomitrescak avatar Dec 09 '19 20:12 tomitrescak

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

zachasme avatar Dec 09 '19 21:12 zachasme

Still happening on ^3.0.0-beta.16

kapolos avatar Jan 01 '20 09:01 kapolos

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

FH-Hersey avatar Jan 23 '20 21:01 FH-Hersey

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

zachasme avatar Jan 24 '20 09:01 zachasme

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

bulutfatih avatar Jan 29 '20 06:01 bulutfatih

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

m1m6 avatar Jan 31 '20 11:01 m1m6

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

robertvorthman avatar Mar 23 '20 00:03 robertvorthman

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?

defg avatar Apr 29 '20 22:04 defg

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

laurenthox avatar May 08 '20 09:05 laurenthox