Reputation: 55
How do I get my useQuery() to fire on both first render as well as on subsequent events (e.g. button click)?
From what I've read, when React mounts a component that calls a useQuery
for the first time, Apollo automatically executes the query, and if I want to execute that query in response to an event, I can instead use useLazyQuery
which returns a function that can be called. What if I want to do both?
Not very sure which part of my understanding of React hooks is incorrect or incomplete, but I've tried with using refetch
in useQuery
, which definitely allows me to call that function, but doesn't seem to always fire upon component mount (the more confusing thing is that sometimes it does, sometimes it doesn't). I'm also using notifyOnNetworkStatusChange
, which I read it needed for refetch
to recognise that it should trigger the onCompleted
part of the useQuery
.
Any help would be much appreciated, I think I don't really understand Hooks at all. Thanks!
P.S. an example of my useQuery
is as follows:
const { refetch: refetchGetTaskTypes } = useQuery(GET_TASK_TYPES(["taskId", "taskType"]), {
notifyOnNetworkStatusChange: true,
onCompleted: (data) => {
if (data !== undefined && data.getTaskTypes !== undefined && data.getTaskTypes !== state.taskTypes) {
dispatch({
type: 'GET_TASK_TYPES',
payload: {
taskTypes: data.getTaskTypes
}
});
}
}
});
P.P.S. as an example of refetch
sometimes needing to be called to render and other times not, I have another useQuery
that is almost identical to the above (with a different query) that also has refetch
, but it renders on first load
P.P.P.S. I sometimes see another issue where refetch
gets outdated data, and I have to use fetchPolicy: 'cache-and-network'
to fix it. It doesn't always happen however
Upvotes: 1
Views: 11725
Reputation: 8418
, but I've tried with using refetch in useQuery, which definitely allows me to call that function, but doesn't seem to always fire upon component mount (the more confusing thing is that sometimes it does, sometimes it doesn't)
... network requests not fired? ... or your onCompleted
conditions not met (no dispatch
then)? No dispatch
doesn't mean not requested/fired ...
onCompleted: (data) => {
if (data !== undefined && data.getTaskTypes !== undefined && data.getTaskTypes !== state.taskTypes) {
onCompleted
is fired when data
exists, no need to test it (data !== undefined
)getTaskTypes
is nullable? If not (IMHO it shouldn't), don't test it, either;data.getTaskTypes !== state.taskTypes
- why don't ask API for this type only? Filtering not supported?Your code is a bit confusing
useQuery(GET_TASK_TYPES(["taskId", "taskType"])
It looks like some generator/function (to define required fields?) - use const instead.
It looks like you are using redux to store received data. Apollo is much smarter (normalizing cache) and doesn't need to write custom actions for each data [type] fetch. You should use Apollo for that but probably you tested it and failed? ...
id
fields?Your tasks doesn't have an id
field but taskId
? Apollo won't write it into cache. Luckily you can help Apollo to recognize unique identifiers in your data - https://www.apollographql.com/docs/react/caching/cache-configuration/#custom-identifiers
After this you can simply use data
from useQuery
for 1st render and refetch
on demand/from event handler (without using useEffect
hook).
Upvotes: 0
Reputation: 1101
Use LazyQuery -
const [getTaskType, { loading, data }] = useLazyQuery(GET_TASK_TYPE, {fetchPolicy: 'network-only'}); // fetch policy is to not look for cache and take the data from network only
To get the data on page load -
useEffect(() => {
getTaskType();
}, []);
To anytime trigger it on button click you can simply call the method. -
<Button
onClick={()=>getTaskType()}>Click Me!
</Button>
Upvotes: 6