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

useLazyQuery ignores fetchPolicy 'network-only' #3355

Closed
fredantell opened this issue Aug 12, 2019 · 23 comments · Fixed by #3453
Closed

useLazyQuery ignores fetchPolicy 'network-only' #3355

fredantell opened this issue Aug 12, 2019 · 23 comments · Fixed by #3453
Assignees

Comments

@fredantell
Copy link

fredantell commented Aug 12, 2019

Intended outcome:

I had a useLazyQuery hook with a fetchPolicy of network-only. I expect that every time I run this I generate a network request and get a new response.

I was using this custom hook and then calling it from a click handler:

  const useCustHook = () => {
    const [executeQuery, result] = useLazyQuery(GQL_QUERY, {
      fetchPolicy: "network-only"
    });
    return async ({ foo }) => {
      await executeQuery({
        variables: { foo },
        fetchPolicy: "network-only"
      });
      console.log("response", result);
      return result;
    };
  };

...and then calling it from a click handler:

function QueryButotn() {
  const lazyQueryFn = useCustHook();
  return (
      <button
        onClick={() => {
          lazyQueryFn({ foo: "bar" });
        }}
      >
        Launch Lazy Query
      </button>
  );
}

Actual outcome:

Actual behavior was to send a network request on the first invocation. Subsequent runs would return the previously returned values and did not generate a network request.

I could fix the issue and get the desired behavior by swapping out useLazyQuery for useApolloClient like so:

const useCustHook = () => {
const client = useApolloClient();
    return async ({ foo }) => {
      const response = await client.query({
        query: GQL_QUERY,
        variables: { foo},
        fetchPolicy: "network-only"
      });
      console.log("Client.query response", response);
    };  }; 

How to reproduce the issue:

I tried to use the codesandbox link to make a repro, but got tripped up on a cross origin error when I tried to update the linked app to use the ApolloProvider from @apollo/react-hooks. I can try again later, but wanted to at least submit.

Version

System:
OS: macOS 10.14.5
Binaries:
Node: 10.16.0 - ~/.nvm/versions/node/v10.16.0/bin/node
Yarn: 1.17.3 - ~/.nvm/versions/node/v10.16.0/bin/yarn
npm: 6.9.0 - ~/.nvm/versions/node/v10.16.0/bin/npm
Browsers:
Chrome: 76.0.3809.100
Safari: 12.1.1
npmPackages:
apollo-cache-inmemory: ^1.6.2 => 1.6.2
apollo-client: ^2.6.3 => 2.6.3
apollo-link: ^1.2.12 => 1.2.12
apollo-link-context: ^1.0.18 => 1.0.18
apollo-link-error: ^1.1.11 => 1.1.11
apollo-link-http: ^1.5.15 => 1.5.15
apollo-link-ws: ^1.0.18 => 1.0.18
apollo-utilities: ^1.3.2 => 1.3.2
react-apollo: ^2.5.8 => 2.5.8

not sure it's included in the output, but using "@apollo/react-hooks": "^3.0.0"

@hwillson hwillson self-assigned this Aug 12, 2019
@tz5514
Copy link

tz5514 commented Aug 15, 2019

Same issue on me.

@alamothe
Copy link

Same problem, but I want to report one more.

If a component is re-rendered, useLazyQuery will re-fire automatically if previously fired. This is undesired behavior.

@manishoo
Copy link

Same problem

@robertotauille
Copy link

same problem

2 similar comments
@faridsaud
Copy link

same problem

@Rockheung
Copy link

same problem

@hwillson
Copy link
Member

hwillson commented Sep 3, 2019

Under the hood, Apollo Client is intentionally blocking subsequent network requests that use the same query, fetch policy and variables. For reference, the relevant parts of the AC codebase are:

https://github.com/apollographql/apollo-client/blob/54e6ea3a1fc07b020c449a7f597a46ca0792d627/packages/apollo-client/src/core/ObservableQuery.ts#L455-L465

https://github.com/apollographql/apollo-client/blob/54e6ea3a1fc07b020c449a7f597a46ca0792d627/packages/apollo-client/src/core/ObservableQuery.ts#L505-L512

This is a known issue (which also happened in RA 2) and is currently by design, but I would like to change it. More details shortly.

@hwillson
Copy link
Member

hwillson commented Sep 3, 2019

I have a temporary patch ready for this on the React Apollo side, that I'll submit shortly. In the not too distant future React Apollo and Apollo Client will be much more tightly integrated (RA is being merged into AC for AC 3), and React Apollo's use of setOptions / setVariables will be revisited.

hwillson added a commit that referenced this issue Sep 3, 2019
Before this commit, calling a `useLazyQuery` exection function
multiple times in a row, when using a fetch policy of
`network-only`, lead to unexpected results. Only the first network
request was submitted as Apollo Client was blocking subsequent
requests, since the query, fetch policy and variables remained
the same. This commmit adds additional cleanup to the
`useLazyQuery` exection function, such that each call will start
a new `ObservableQuery` instance. This means each query fired
by the `useLazyQuery` execution function is treated as a fully
new query.

Fixes #3355.
hwillson added a commit that referenced this issue Sep 3, 2019
…3453)

* Better support for multiple `useLazyQuery` execution function calls

Before this commit, calling a `useLazyQuery` exection function
multiple times in a row, when using a fetch policy of
`network-only`, lead to unexpected results. Only the first network
request was submitted as Apollo Client was blocking subsequent
requests, since the query, fetch policy and variables remained
the same. This commmit adds additional cleanup to the
`useLazyQuery` exection function, such that each call will start
a new `ObservableQuery` instance. This means each query fired
by the `useLazyQuery` execution function is treated as a fully
new query.

Fixes #3355.

* Changelog update
@ramHruday
Copy link

ramHruday commented Feb 25, 2020

I am still facing this issue :(
apollo/react-hooks 3.1.3

@hwillson

@Fen747
Copy link

Fen747 commented Feb 27, 2020

Still facing it.... That's a very, very problematic bug :/

@Rodrigo816
Copy link

this is really problematic.
I have the same problem

@ConnorTCM
Copy link

Still experiencing this issue when using useLazyQuery.
apollo-client: 2.6.8
@apollo/react-hooks: 4.0.0-beta.1

@mikeyrt16
Copy link

I'm still experiencing this issue. @apollo/client 3.0.0-beta.38. This is blocking desirable behaviour of our app... Does anyone have a hacky workaround for time being?

@ConnorTCM
Copy link

@mikeyrt16 My use case for useLazyQuery was to synchronously wait for a prop to be populated (via a different query higher up the tree) before executing the query like this:

const ChildComponent = ({ id }) => {
  const [getData, { data, loading, error }] = useLazyQuery(QUERY, {
    fetchPolicy: `network-only`,
  });

  useEffect(() => {
    if (id) {
      getData({ variables: { id } });
    }
  }, [id, getData]);
  ...

As useQuery is unaffected by this bug, I've resorted to switching out useLazyQuery to useQuery, removing my useEffect hook and then only rendering the component if the condition is met in the parent component. I've had to re-jig various loading/error states too but it is an interim solution.

const ParentComponent = ({ id }) => {
  return (
    <div>
      {id && (
        <ChildComponent id={id} />
      )}
    </div>
  );
};

export const ChildComponent = ({ id }) => {
  const { data, loading, error } = useQuery(QUERY, {
    fetchPolicy: `network-only`,
    variables: {
      id,
    },
  });
  ...

I'm not sure what you could do if you wanted to call the query after an event, I haven't ran into that situation yet I'm afraid.

@Carrie999
Copy link

same problem

@johnparn
Copy link

Noticed the same problem. I use 'no-cache' instead as it works well for my case.

@basicBrogrammer
Copy link

Network-only was working for me about a month ago. Now it's not. Gonna try to pin point what change broke it

@flieks
Copy link

flieks commented Jun 26, 2020

For me it works

@kohloth
Copy link

kohloth commented Jun 29, 2020

Still an issue.

A query created using useLazyQuery will run whenever a component is re-rendered, but it should only run when invoked manually, as the docs describe.

Currently, the server is being hit with a request every time the user types in the search box.

Getting this to work right will involve some really verbose hook state juggling.

@gsofter
Copy link

gsofter commented Jul 5, 2020

Same problem with me.
BTW, who can explain about fetchPolicy attribute?

@kohloth
Copy link

kohloth commented Jul 5, 2020

Same problem with me.
BTW, who can explain about fetchPolicy attribute?

Not sure about fetchPolicy, but as for fixing the unlaziness, wrapping the state var that useLazyQuery watches with useDebounce patched the problem for me.

https://usehooks.com/useDebounce/

const [searchTerm, setSearchTerm] = useState('');
const debouncedSearchTerm = useDebounce(searchTerm, 500);
useEffect(() => {
  // Invoke the query here
}, [debouncedSearchTerm]);

@michelalbers
Copy link

I have a query where I generate an upload URL for the user on S3. I ended up adding a "salt" field with which I don't anything other than filling it with a random value on the client side. That way the request is not blocked. Anyway - I think when stating network-only apollo should not interfere in any way with that config option. The current behavior is quite confusing.

Temporary solution

s3.graphql

extend type Query {
  getS3UploadURL(salt: String!): String!
}

getS3UploadURL.ts

// Not using salt here at all
export default async (_: any, __: any, { aws } : MyContext) => {
  return aws.awesomeLinkLogic({ foo: "bar" });
}

myComponent.tsx

/* ... */

const [doLoadURL, s3UploadURLResult] = useLazyQuery(s3Query, { fetchPolicy: 'network-only' });

/* ... */

// Include any random string, so the cache is not used
doLoadURL({ variables: {  salt: Math.random().toString() } });

/* ... */

@basicBrogrammer
Copy link

Its no longer an issue for me. I found out it was bc ionic only unmounts React components when the direction is "back" which is an odd choice but deliberate.

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

Successfully merging a pull request may close this issue.