TanStackT
TanStack3y ago
9 replies
skinny-azure

useQueryClient inside a custom hook

Hi,
I'm pretty new to React Query. I've done a pretty solid scan of docs, StackOverflow and the archive of QA here.

I've got a CRUD app with 'parent' queries (arrays of a given data type) and 'child' queries (a single instance of a data type). When mutating a child, I want both of the corresponding queries to update using
setQueryData
. To encapsulate this behaviour, I've written a custom hook, that can be called from within a component (ie when an edit form is submitted).

Custom hook:


const { useMutation, useQueryClient } = require("@tanstack/react-query");

function useMutateAndUpdate({parentQueryKey, childQueryKey, mutateFunction, isNew = false, onSuccess}) {
  
  const queryClient = useQueryClient();

  const mutation = useMutation({
    mutationFn: (data) => mutateFunction(data),
    onSuccess: ({screen: data}) => {
      // do some stuff to setQueryData in parent and child queries
      onSuccess(data);
    } 
  })
  return mutation;
}

export {useMutateAndUpdate}


Hook usage


I then call it from within my component with
const saveOrUpdate = useMutateAndUpdate({
    parentQueryKey: ['screens'],
    childQueryKey: ['screens', {id: screen.id || 'new'}],
    mutateFunction: screenActions.saveOrUpdate,
    onSuccess: (data) => navigate(`/screens/${data.id}`),
    isNew: _.isEmpty(screen.id)
  });


I'd like to reuse this for various data types, and cover off the 'create a new' as well as the 'update an existing' use case.

The custom hook throws an error that

No QueryClient set, use QueryClientProvider to set one

This isn't the case, there is definitely a
QueryClientProvider
wrapping my app. I'm not sure why it would be inaccessible inside the hook.

I can work around this by passing the result of useQueryClient into the custom hook, but is that the only way this can work? Other hooks like
useState
can be used in a custom hook, so I'm not sure what I'm doing wrong here.
Was this page helpful?