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"
Same issue on me.
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.
Same problem
same problem
same problem
same problem
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:
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.
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.
I am still facing this issue :(
apollo/react-hooks 3.1.3
@hwillson
Still facing it.... That's a very, very problematic bug :/
this is really problematic.
I have the same problem
Still experiencing this issue when using useLazyQuery.
apollo-client: 2.6.8
@apollo/react-hooks: 4.0.0-beta.1
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?
@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.
same problem
Noticed the same problem. I use 'no-cache' instead as it works well for my case.
Network-only was working for me about a month ago. Now it's not. Gonna try to pin point what change broke it
For me it works
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.
Same problem with me.
BTW, who can explain about fetchPolicy attribute?
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]);
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() } });
/* ... */
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.
Most helpful comment
Same problem, but I want to report one more.
If a component is re-rendered,
useLazyQuerywill re-fire automatically if previously fired. This is undesired behavior.