Reputation: 541
I'm a bit baffled here. According to this SO question and also this question, I should be able to call the useEffect
hook after calling the useQuery
hook to populate state, which I am doing via useReducer
. E.g., something like this (assume that foo
, bar
, and baz
are named queries within a single request to the GraphQL server):
const MyComponent = ( props ) => {
const [ state, dispatch ] = useReducer( reducer, initialState )
const query = someCondition ? query1 : query2
const variables = { variables: someCondition ? query1Vars : query2Vars }
const { loading, error, data } = useQuery( query, variables )
useEffect(function() {
dispatch({
type: types.INIT,
payload: {
foo: data.foo,
bar: data.bar,
baz: data.baz
}
})
}, [data])
return (
<div>
{
(() => {
if ( loading ) return <Loading />
if ( error ) return <Error />
return (
// components that depend on data
)
})()
}
</div>
)
}
For reasons I can't determine, data
is undefined
when I reference it inside useEffect
. I have checked my network responses and the call to my GraphQL endpoint is indeed returning data. (Essentially, what's described in this other SO question about useQuery.)
Except for the conditional query/variable assignment, this code is in use for some of our other components and it works fine, so I have no idea why it's not working in my case.
I'm not sure what's going on here, as I've made sure that no hooks are being called conditionally, in violation of the rules of hooks; all I'm doing is conditionally assigning variable values before sending the query via Apollo client. (I also tried the onCompleted
property of the useQuery
options, without the useEffect
hook, but to no avail; data
is still undefined
.)
Upvotes: 3
Views: 6787
Reputation: 82096
Unless I'm not fully understanding your issue, this looks like expected behaviour.
useEffect
will fire on mount and then anytime data
changes, data
will only change when the API call has completed. The initial useEffect
call is going to happen before useQuery
has gotten a response from the server therefore you can't assume inside useEffect
that data
will be set.
If you only want to dispatch when data
is there then you should protect the call e.g.
useEffect(() => {
if (data) {
dispatch({
type: types.INIT,
payload: {
foo: data.foo,
bar: data.bar,
baz: data.baz
}
});
}
}, [data]);
Upvotes: 3