useLazyQuery refetch will never resolve the promise even network request done
Query hook
const [getTopicById] = useLazyQuery<
{ topic: Topic },
{ topicId: string }
>(GET_TOPIC_DETAIL_BY_ID_QUERY,{
fetchPolicy:'cache-and-network',
// or network-only
})
Function to call the query
try {
console.log("start handleGetTopicDetail")
const result = await getTopicById({
variables:{
topicId
}
})
console.log("result handleGetTopicDetail", result)
console.log("end handleGetTopicDetail");
} catch (error) {
console.log("error", error);
}
Intended outcome: I expect it will run the query, then resolve the promise, if error then throw it and print to the console
Actual outcome:
When the query run the first time, it is good whatever the fetch policy is.

When run 2nd time or more:
The query network request is done, but never resolve Promise to pass the await. You can see the result never print

How to reproduce the issue:
Versions
System:
OS: Linux 5.4 Ubuntu 20.04.2 LTS (Focal Fossa)
Binaries:
Node: 16.13.1 - ~/.nvm/versions/node/v16.13.1/bin/node
Yarn: 1.22.15 - ~/.yarn/bin/yarn
npm: 8.1.2 - ~/.nvm/versions/node/v16.13.1/bin/npm
npmPackages:
@apollo/client: ^3.5.6 => 3.5.6
This behavior also happen in "network-only" fetch policy And interesting is, if i send the 2nd or more request with same function, the 2nd will work while 1st one is jammed
I do further test and add a Dummy button for re-fetch. The useEffect is first load, the Dummy button is for re-fetch
useEffect(() => {
param.topicId ? handleGetTopicDetail(param.topicId) : setTopic(null)
}, [param.topicId])
return (
<Fragment>
<button
onClick={async () => {
console.log("ress start")
const res = await getTopicById({
variables: {
topicId: param.topicId,
},
})
console.log("ress end", res)
}}
>
Dummy
</button>
{topic && (
<Fragment>
<TopicDetailContainer
topic={topic}
onRefresh={async () =>
await handleGetTopicDetail(topic.id, true)
}
/>
</Fragment>
)}
</Fragment>
)
The 1st request is OK, and load data i need
The 2nd re-fetch is jammed

If i send 3rd re-fetch, it can pass again

We are having this same issue.
Experiencing the same on 3.5.7
don't know if this bug solved or not, below is a customLazyQuery work perfectly for async, credit to someone in other threads (sorry i forget who and where but it is useful, thank you !
import { DocumentNode, OperationVariables, useApolloClient } from '@apollo/client';
import { useCallback } from 'react';
export function useCustomLazyQuery<TData = any, TVariables = OperationVariables>(_query: DocumentNode) {
const client = useApolloClient();
return useCallback(
(variables: TVariables) =>
client.query<TData, TVariables>({
query: _query,
variables: variables,
fetchPolicy:'network-only',
}),
[client, _query]
);
}
We are having the same issue on 3.3.20
Same issue - although ours is also hanging on the first request. Returned updated data is still available from the hook such as data, error, loading etc.
Investigated this a little over the weekend, I think our issue is down to the Apollo client changing after our component is rendered (from an unauthed client to an authed one). Could be worth checking that your client is memoized or similar?
having the similar issue.
useLazyQuery returns a tuple with a LazyQueryExecFunction, which returns a promise that is never resolved.
Apollo client v3.7.3
The solution offered by @jackykwandesign works as a good bypass. Thank you.
I managed to workaround this issue - TL;DR: I used a combination of notifyOnNetworkStatusChange: true and onCompleted options instead of awaiting the lazy query to resolve.
I'm implementing a debounceLazyQuery where I need to track of my own loading flag from the beginning of debounce until the call is actually made. This got tricky when the lazy query call never resolves - even though the API correctly responds - I don't know when the loading is finished.
Turns out, setting notifyOnNetworkStatusChange to true makes the lazy query trigger onCompleted when the API response arrives, passing the same data fetch would have been resolved with (?seemingly) as a parameter.
Here's some code for the reference:
const [data, setData] = useState<Q>();
const [isLoading, setLoading] = useState(false);
const [fetch, queryResult] = useLazyQuery<Q, V>(query, queryOptions);
const debounceTimeout = useRef<any>();
...
const debouncedFetch: QueryTuple<Q, V>[0] = useCallback(
(options?: QueryLazyOptions<V>) =>
new Promise(resolve => {
const opts = {
notifyOnNetworkStatusChange: true, // <-- add this to make onCompleted called when API responds
...options,
onCompleted: (nextData: Q) => { // <-- use onComplete to handle the response
setLoading(false);
setData(nextData);
},
};
setLoading(true);
clearTimeout(debounceTimeout.current);
debounceTimeout.current = setTimeout(async () => {
resolve(fetch(opts)); // <-- this fetch may never resolve - the issue
}, debounceMs);
}),
[debounceMs, fetch],
);
Hey @jackykwandesign 👋
I know its been some time since you've opened this issue so appreciate the patience here! Without a reproduction its difficult to tell if this has already been fixed, but I'd like to point you to a couple fixes that dealt with unresolved promises in useLazyQuery. These fixes may or may not be related to the issue you were seeing.
3.7.4 fixed an issue via https://github.com/apollographql/apollo-client/pull/10427 that rejects promises when the component unmounts. Given what I see in your code sample, I don't think this has to do with unmounting, but there is a chance the same underlying mechanism was at play.
Unfortunately my original approach in 3.7.4 was met with a bit of pushback as aborting the request and rejecting the promise proved to be unpopular for various reasons. 3.7.11 tweaked this behavior via https://github.com/apollographql/apollo-client/pull/10698 so that it allows the promise to resolve naturally, regardless of whether the component had been unmounted or not.
I'd love if you'd be able to try 3.7.11 or later and see if your issue has been resolved. Thanks!
We're closing this issue now but feel free to ping the maintainers or open a new issue if you still need support. Thank you!
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.