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?
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 }) }, []);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With