Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use useQuery when a state variable changes

I have following structure in a react app:

<SomeProvider id={objectId}>
  <SomeApp />
</SomeProvider>

This provider uses a useQuery to fetch an object from the backend. With useContext I make it accessible to all the components of the app:

const EventProvider = ({ id, children }) => {
  const {data} = useQuery(SOME_QUERY, { variables: input })
  const obj = data ? data.something : {}

  // etc.
}

export const useSomething = () => {
  // etc.
}

In a component I can have access to this object:

const Component = ({id}) => {
  const { obj } = useSomething()
}

Until here all working. My question is, inside this component, I have a button that changes this object in the backend.

How can I fetch the obj again?

I can of course refresh the page, but this is the solution that I want to avoid. What I've tried so far is:

Try to use the useQuery again in the Component.

 const Component = ({id}) => {
   const { obj } = useSomething()

   const {data} = useQuery(SOME_QUERY, { variables: input })
      const obj = data ? data.something : {}
 }

But actually what I would like to do is trigger the query when a State variable changes:

const Component = ({id}) => {
  const { obj } = useSomething()
  const { isActivated } = useOtherHook()

  const {data} = useQuery(SOME_QUERY, { variables: input })
      const obj = data ? data.something : {}

  useEffect(() => {
    // when isActivated changes, I would like to fetch the obj again
  }, [isActivated])
}

If I use useQuery inside of useEffect, I get:

Hooks can only be called inside of the body of a function component

What is the best approach to solve this challenge?

like image 213
AlbertMunichMar Avatar asked Feb 04 '23 15:02

AlbertMunichMar


1 Answers

The reason for the error messages you get is, that you can only use hooks in the body of your component, not inside of other functions that are not hooks, nor inside of conditions. You can read more about that here in the rules of hooks

As you can read in the documentation for useQuery here, there are multiple ways of keeping data up to date or refetching.


The easiest way of keeping data up to date would be to use the polling feature from apollo.

const { loading, error, data } = useQuery(QUERY, {
    variables: input,
    skip: !isActivated,
    pollInterval: 500, // Update every 500ms
  });

One way of refetching on demand would be to use the returned refetch function.

const { loading, error, data, refetch } = useQuery(/* ... */);
useEffect(() => { refetch() }, [isActivated])

Depending on your needs, you could also use the useLazyQuery hook. This does not fetch data on render but only on function call. This is most useful when you want to only request data when the input has been set or changed.

const [getData, { loading, data }] = useLazyQuery(QUERY);

useEffect(() => { getData({ variables: input }) }, []);
like image 138
Linschlager Avatar answered Apr 06 '23 07:04

Linschlager