diekunstderfuge
diekunstderfuge

Reputation: 541

useQuery data undefined when calling useEffect hook?

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

Answers (1)

James
James

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

Related Questions