-
Notifications
You must be signed in to change notification settings - Fork 7
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
Lazy useQuery #119
Comments
I really like this idea @FredyC! I'll discuss this further with the team. Thanks! |
I ran into two issues with the current implementation of useQuery. const { data, loading, error } = useQuery(SOME_GQL, { When prop.id is empty, I don't want to run the query. But my functional component has to run useQuery since useQuery as a hook cannot be wrapped in a conditional statement. The order of hooks must be always same. I have a refresh icon. Clicking on it should refetch the data. But there is no way to trigger the useQuery again. I wrote a dummy mutation and set its refetchQueries. Yes 2 full round trips. |
@stonebat You can use |
For the loading state issue, maybe it's possible to introduce a new state variable like Elm does, |
Initial work to support deferring `useQuery` execution until some point in the future (after `useQuery` has been initialized). If a `lazy` option is set to a boolean, `useQuery` will return a tuple instead of a result object. The first position of the tuple is the standard query result object, and the second position is a function that can be triggered to kickstart the normal `useQuery` query cycle. If `lazy` is `true`, the initial query result with have a `loading` status of `false`, and a `data` value of `undefined`. This will only change after query execution has been triggered using the delayed start function. If `lazy` is `false`, a tuple is still returned, but `useQuery` will still fire immediately (similar to calling `useQuery` without a `lazy` option). Fixes apollographql/apollo-feature-requests#119.
I've kickstarted this work in apollographql/react-apollo#3214. There is still work to do for sure (dealing with |
I think that you could totally remove |
@marconucara That's not the brightest idea, because you would end up in endless loop :) Execute would cause re-render and then you would call execute again... You would need The skip, on the other hand, has its uses as well, for example when the query depends on some other data you don't have just yet. |
@FredyC Thanks! Invoking refetch from useQuery worked for my case. No more dummy mutation :) |
Of course I was wrong, you will need useEffect ad it will probably become too much. I'm still thinking that Also what should happened if you change |
Perhaps I am missing some more obvious solutions and patterns. Would love to hear about those :)
The problem
The known "problem" of hooks is an inability to call them conditionally. At the moment query needs to be executed conditionally based on user action (or some other side effect), it requires extra ceremony to the component. Value to be searched needs to be stored to state first to let
useQuery
notice it on next render AND theskip
needs to be used to avoid calling query when it's not intended.Workaround
Use the
Query
component (or write one with useQuery) which can be rendered conditionally. The render prop pattern does not fit well in the hooks world. It also requires writing the result into a state to re-render a whole component based on it. Lastly, conditional rendering can cause unnecessary DOM trashing if not treated carefully.Poor solution
Grab the
useApolloClient
and callclient.query
directly. Once again it requires storing results into a state when an operation is done. Also tracking the "loading" and "error" means solving something that's already solved more carefully (within useQuery).A custom hook like that can surely be tackled in user-land (and I do that), but it leaves an ugly blind spot for newcomers and possible bugs that might be solved better in a community solution.
Better solution
Add
lazy
option touseQuery
and provideexecute
function. It will provide a nice declarative approach we are used to without any extra ceremony.What needs to be solved is the initial
loading
state in such a case. It should befalse
probably.Also, would be nice to get
called
prop similar to whatuseMutation
has. That can be useful for a different rendering based on that, eg. instructions to the user. The "non-lazy" mode will toggle it totrue
pretty much immediately.What happens when
skip
andlazy
are used together? What willexecute
do? Should be an invariant error most likely. Or execute forcefully even over the skip?How does it work together with polling? The first call to
execute
could be used to start polling. Subsequent ones could be for changing variables and interval and restarting polling.The text was updated successfully, but these errors were encountered: