Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useLazyQuery run after component rerender #7484

Open
Tracked by #8596
pronovaso opened this issue Dec 15, 2020 · 37 comments
Open
Tracked by #8596

useLazyQuery run after component rerender #7484

pronovaso opened this issue Dec 15, 2020 · 37 comments

Comments

@pronovaso
Copy link

Hi all.

I switch to new version of Apollo client. Actually v 3.3.6.

I use useLazyQuery in component with useQuery and useMutation. If I clicked on button,which open confirm window,then I call useLazyQuery function called load({variables:{id}}), query runs and give me a data. Thats right.But after run some mutation and query for new data from useQuery, than useLazyQuery runs again with same id. But load function is on handleClick, which not fire and this id is only from this handleClick.

And I dont know why. One difference is, new inMemoryCache. When I use this from package apollo-inmemory cache and not from @apollo/client than everything is allright.

Can you someone explain me, what I doing wrong or maybe bug in InMemoryCache?

Thans and sorry for my english :-)

@hyperxpizza
Copy link

Similar issue here. UseLazyQuery seems to send a request to the server everytime my component re-renders.

"@apollo/client": "^3.3.6",
"@apollo/react-hooks": "^3.1.3",

@aub
Copy link

aub commented Jan 14, 2021

Same here

@pedrochiossi
Copy link

Also having this problem, fired lazyQuery, after it finishes, other queries run in sequence, some are even using old variables from previous calls. Seems to be a problem in cache handling, it works if I use the "no-cache" fetchPolicy.

@pronovaso
Copy link
Author

Also having this problem, fired lazyQuery, after it finishes, other queries run in sequence, some are even using old variables from previous calls. Seems to be a problem in cache handling, it works if I use the "no-cache" fetchPolicy.

Yes same here. In my case, if I change fetchPolicy to "no-cache" and query runs, I have same old value.
For example....I create a new request in form and then run fetch some query, network request will place, but in menu, where should change number from request, I have same old number.

@dlindahl
Copy link

I believe I am experiencing this same issue. I have a useLazyQuery with a fetch policy of network-only that, once it has been explicitly executed once by a user interaction, is making additional network requests over the wire whenever the component re-renders, even though the execute function, nor the refetch function, have been explicitly called.

After poking around a bit in useBaseQuery, it looks like a forceUpdate is getting triggered with an increase in the tick value even though none of the lazy query's variables are changing in the host component. I have confirmed this behavior by hardcoding the query variable values to primitives so that they always have referential equality. In that scenario, I would never expect a lazy query to re-execute unless explicitly asked to via the execute function or refetch.

@aquelehugo
Copy link

I think we can use nextFetchPolicy: 'cache-first', as a workaround, just so network requests are avoided. But it is a bug a for sure

@limekiln
Copy link

limekiln commented Jun 8, 2021

I am experiencing this as well, although, for some reason, only if the previous intended call of the lazy query returns an error. If the query resolves corretly and returns data, no follow up requests are made.

@robinjhuang
Copy link

Also having the same issue. useLazyQuery re-runs the query on component re-render.

@andremoah
Copy link

andremoah commented Jul 11, 2021

This issue is also happening to me and it seems a bug since the documentation states "The useLazyQuery hook is perfect for executing queries in response to events other than component rendering."

I have tried every type of fetchPolicy without any success (even though it does not feel right because it still creates a new network request), the requests are always re-executed on component render resulting in data going back to undefined and then to the new request request (onCompleted is always re-executed as well).

This totally invalidates the objective and usage of useLazyQuery.

@assimovt
Copy link

assimovt commented Aug 4, 2021

same issue here

@brainkim brainkim mentioned this issue Aug 13, 2021
14 tasks
@hwillson hwillson added this to the Release 3.5 milestone Sep 7, 2021
@hwillson hwillson added 2021-09 and removed 2021-08 labels Sep 7, 2021
@Pedro-Puga
Copy link

Pedro-Puga commented Sep 8, 2021

When does the 3.5 release go live? I have the same issue when using conditionally two different lazyQueries inside a useEffect when all lazyQueries have been executed previously whenever I call one of them the other one is being executed without being called, very weird.

@brainkim
Copy link
Contributor

@Pedro-Puga Are you confirming that this issue (or a separate issue you have) is fixed by 3.5? We’re planning on releasing 3.5 on the 27th, so if you’d like to try the beta by installing @apollo/client@beta, I would be eternally grateful!

@Pedro-Puga
Copy link

@Pedro-Puga Are you confirming that this issue (or a separate issue you have) is fixed by 3.5? We’re planning on releasing 3.5 on the 27th, so if you’d like to try the beta by installing @apollo/client@beta, I would be eternally grateful!

No... my comment was before trying your beta, I'm sorry, I tried using the v3.5.0-beta.11 and the issue still persist, I can try to help you having a quick call next week to see exactly what my use case is and try to solve it, but this new beta version does not fix my issue.

@aub
Copy link

aub commented Sep 13, 2021

I have also been having this problem but just discovered something that might be the cause. I have a React component that builds out the ApolloClient and creates all of its various links. I found that some of the links were not memoized and so were being rebuilt with each render, and also that I was incorrectly setting the dependencies for the useMemo hooks that created the links so that they would be regenerated way too often as well. Cleaning that up seems to have totally solved the problem for me. If you're having this problem, try memoizing everything and narrowing those dependencies as much as possible to reduce rebuilds of the client.

@pronovaso pronovaso reopened this Sep 13, 2021
@pronovaso
Copy link
Author

pronovaso commented Sep 13, 2021

@aub ...setting the dependencies for the useMemo hooks...

I'm so sorry form my mistake (closing this issue ) . I'm very tired I guess :-)
In my case, useMemo not used. That's not the problem.

@aub
Copy link

aub commented Sep 14, 2021

I guess all I'm trying to say is that while I don't know exactly why the problem occurs, it does seem to be triggered in my case by frequently rebuilding the ApolloClient. I don't think useMemo specifically is the problem, but it can be a solution to the problem if used properly because it can cut down on those rebuilds.

@brainkim
Copy link
Contributor

Hey everyone!

I had a call with @Pedro-Puga last week about useLazyQuery() which gave me some insight into the problem people in this issue are facing. So one thing that might not be known is that once the useLazyQuery() hook begins executing, it behaves more or less exactly like useQuery(). So if you update the variables, or if you have polling, or do any sort of cache invalidation or updating, the query will run again. I know this is confusing but that’s the way this hook was designed. This is probably the thing people in this issue are struggling with. Think of the execution function as starting the query, not controlling exactly when the query runs.

As an alternative, you can use useQuery with the skip option to prevent the query from being run when you don’t want it to be run.

Another odd detail about useLazyQuery()’s design is that we don’t allow passing the skip option, even though the query now behaves like a normal query. I think we’ll probably add this to useLazyQuery() soon.

@hwillson hwillson removed this from the Release 3.5 milestone Sep 28, 2021
@sflahave
Copy link

sflahave commented Oct 2, 2021

Wow, thanks for that explanation @brainkim! I think it'd be really helpful to add to the documentation for useLazyQuery. Even after reading your explanation, the way the documentation describes useLazyQuery suggests (to my mind) that the query will only be executed when you explicitly call the function it provides.

@pronovaso
Copy link
Author

Hey everyone!

I had a call with @Pedro-Puga last week about useLazyQuery() which gave me some insight into the problem people in this issue are facing. So one thing that might not be known is that once the useLazyQuery() hook begins executing, it behaves more or less exactly like useQuery(). So if you update the variables, or if you have polling, or do any sort of cache invalidation or updating, the query will run again. I know this is confusing but that’s the way this hook was designed. This is probably the thing people in this issue are struggling with. Think of the execution function as starting the query, not controlling exactly when the query runs.

As an alternative, you can use useQuery with the skip option to prevent the query from being run when you don’t want it to be run.

Another odd detail about useLazyQuery()’s design is that we don’t allow passing the skip option, even though the query now behaves like a normal query. I think we’ll probably add this to useLazyQuery() soon.

But in previous version of Apollo, this issue was not exist.In my case, this useLazyQuery is launched only with click the button and variable is handed over v onClick handler.And this variable are not changed.Is it primitive value. Your explanation does not make sense or I dont understand useLazyQuery. Another thing is Apollo cache. Which is horible.

@sflahave
Copy link

sflahave commented Oct 2, 2021

@pronovaso - I think I had the same problem you described, which is why I found this issue. I'm not commenting as to whether this should be considered a bug or not. Instead I'll just provide the work-arounds that seem to resolve the issue for me. I am using Apollo Client v3.4.0, btw.

I found two techniques to prevent the useLazyQuery from firing automatically after my useMutation call updated the cache:

  1. Use the following fetch policies on the useLazyQuery:
fetchPolicy: "network-only",
nextFetchPolicy: "cache-first",

That seems to work for me. (Previously I had it set up with fetchPolich: "cache-and-network" )

  1. Another option is to use the onQueryUpdated option on my useMutation:
onQueryUpdated: (observableQuery) => {
  return observableQuery.queryName !== "LazyQueryName"
},

That seems to work too, but I don't like it as much as option 1 because it seems to rely too heavily on the query name which is otherwise pretty arbitrary.

Hopefully this helps you.

@manuFL
Copy link

manuFL commented Dec 20, 2021

I totally agree with @pronovaso , this behaviour doesn't make sense with useLazyQuery. Moreover, this issue is not properly workarounded yet, apart from use useQuery instead with cumbersome "skip" logics... this issue has been open for an year now and I think it should be addressed ASAP...

@atomless
Copy link

I have to fully support @manuFL @pronovaso stance on this. The expected behaviour of useLazyQuery is that requests are entirely manual and under the control of the application logic and not automatic in any way. Persisting with this odd pattern of behaviour and ignoring such a significant bug for this long after it has been identified does not inspire confidence in the library in general.

@Drewlove
Copy link

Drewlove commented Apr 18, 2022

Fully support @atomless , @manuFL @pronovaso and others.

Is there an update to this? I feel like I must be missing something here. I don't understand how something as widely adopted as Apollo Client does not have a simple way to only fetch data on user event, as opposed to fetching data automatically every time the component renders.

@dylanwulf
Copy link
Contributor

If you're just looking to fetch data once, I think you can do something like this:

const client = useApolloClient();
const someEventHandler = async () => {
    const queryResult = await client.query({ ...queryOptions });
    // do something with queryResult
};

@aub
Copy link

aub commented Apr 18, 2022

FWIW, I've found that this seems to be fixed in the 3.6 beta builds. I was also having a problem where useLazyQuery would seem to skip the cache and that seems to be fixed as well. I wish I had some idea about the release schedule for that version, but they're getting pretty high up in the beta release numbers and have been releasing betas for 5 months.

@benjamn
Copy link
Member

benjamn commented Apr 19, 2022

Thanks for trying the betas @aub (and @dylanwulf and possibly others in this thread)! Those time windows would be shorter if more folks gave feedback (positive or negative) on the beta/RC releases.

The good news is that we're on @apollo/[email protected] right now, aiming to finalize the v3.6 release by the end of this week, as long as we don't find any new show-stopping bugs. Please try running npm i @apollo/client@beta when you have the chance, since we (believe we have) fixed multiple useLazyQuery bugs in the v3.6 release.

@aub
Copy link

aub commented Apr 25, 2022

@benjamn FWIW I've been using 3.6 rc1 and it's working great while solving all of the issues I've had related to useLazyQuery

@hwillson hwillson added the 🔍 investigate Investigate further label May 31, 2022
@geiszla
Copy link

geiszla commented Jun 6, 2022

We still have this issue on @apollo/client: 3.6.6. We only use the refetch function from useLazyQuery (so that we can await and get back the result from the function call) and after the first refetch call with the proper variables it starts to send requests of the same GraphQL query but with an empty variable object.

A workaround we currently use is setting fetchPolicy: 'cache-only'.

@dnovacik
Copy link

I have also been having this problem but just discovered something that might be the cause. I have a React component that builds out the ApolloClient and creates all of its various links. I found that some of the links were not memoized and so were being rebuilt with each render, and also that I was incorrectly setting the dependencies for the useMemo hooks that created the links so that they would be regenerated way too often as well. Cleaning that up seems to have totally solved the problem for me. If you're having this problem, try memoizing everything and narrowing those dependencies as much as possible to reduce rebuilds of the client.

Sorry to revive this but would you mind providing an example? I seem to be bumping into something similar, but not quite sure how to tackle this.

@okanji
Copy link

okanji commented Nov 10, 2022

@aub an example of the above would be very helpful, thanks

@aub
Copy link

aub commented Nov 10, 2022

@okanji it was fixed for me in 3.6, as noted, so I'm happy. 😀

@yogeshu
Copy link

yogeshu commented Nov 25, 2022

I am still facing this issue, please share if anyone have a good idea

@amerikan
Copy link

amerikan commented Dec 1, 2022

For me this temp workaround solved it for now: #5912 (comment)

@joseeavrs
Copy link

I know that a lot of time has passed since the beginning of this topic, but I thought that I also had this same problem, my solution was to pass the useLazyQuery variables to the execution function, I hope anyone else can be of help.

@saver711
Copy link

Sooo, same issue !!!

@saver711
Copy link

saver711 commented Jun 17, 2023

I have a convenient Solution for this.
just pass the variables to the function that calls the query, not directly to the hook.
const [name, setName] = useState("ahmed")

const [fire, { data, loading, error, called }] = useLazyQuery<People>( GET_PEOPLE )

Call the function
const submitHandler = (e: FormEvent) => { e.preventDefault() fire({ variables:{ name } }) }

@jenya239
Copy link

For me it was enough to leave the variables immutable

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

No branches or pull requests