Misha Moroshko
Misha Moroshko

Reputation: 171389

How to get access to useQuery refetch method from other components?

NextJS app, renders a Header plus one of the Homepage/Contacts/About pages:

Simplified _app.tsx

export default function MyApp({ Component, pageProps }: Props) {
  return (
    <>
      <Header />
      <Component {...pageProps} />
    </>
  );
}

The Contacts page has several filters and it uses a custom useContacts hook (which uses useQuery from react-query) to fetch and render the matched contacts.

Simplified Contacts page

export default function ContactsPage() {
  const [filters, setFilters] = useState(...);
  const contactsInfo = useContacts(filters);

  // render matched contacts
}

The Header has a button which invokes a modal that allows searching people on the platform and adding them as contacts.

When a contact is added successfully, and the user is on the Contacts page, I'd like to refetch the contacts (with all the currently selected filters) so that the newly added contact is immediately visible on the page (assuming they pass the currently selected filters).

It feels that I'd like to call contactsInfo.refetch() somehow, but I don't have access to contactsInfo in Header.

Add to contact success callback

onSuccess: () => {
  if (isContactsPage()) { // assume we have a way to identify this
    // How can I have access to `contactsInfo` here?
    contactsInfo.refetch();
  }
}

Any tips how to best structure this?

Upvotes: 5

Views: 4780

Answers (2)

Chad S.
Chad S.

Reputation: 6633

When a contact is added successfully, and the user is on the Contacts page, I'd like to refetch the contacts (with all the currently selected filters) so that the newly added contact is immediately visible on the page (assuming they pass the currently selected filters).

The correct way to handle this is to invalidate the query. This can be done from anywhere in the application and will only cause a re-fetch if the query being invalidated is active. In this way it's safe to invalidate the query in cases where it would not be efficient to re-fetch.

e.g. in your mutation hook...

   const queryClient = useQueryClient();
   const onSuccess = () => queryClient.invalidateQueries(contactsQueryKey);
   //.. pass the onSuccess to the options of the useMutation hook.

Upvotes: 7

Tuan
Tuan

Reputation: 2433

In mycase, i use queryClient.refetchQueries to conditioned refetch multiple query outside my component.

For example

queryClient.refetchQueries({
  predicate: (query) => {
    // Every query was called in app life will be trigger once, return true to refetch it query.
    
    // Example: all query was get students will be refetch, whatever class they are
    if(query.queryKey.includes('students')){
      return true;
    }
    
    // Example: only query was get students in classRoomId="001" will be refetch
    if(query.queryKey.includes('students') && query.queryKey.includes('001')){
      return true;
    }
  }
})

Easest way for queryKey is bind your query by a unique named and parameter will make every query unique and easy to find.

export const useStudentsQuery = (classRoomId: string) => {
  return useQuery(
    ['students', classRoomId], // <- queryKey
    async () => {
      const res = await http.getAsync<undefined, Student[]>(`class/${classRoomId}/students`);
      return res.data;
    },
    {
      enabled: !!classRoomId,
    }
  );
};

Learn more about refetchQueries.

Upvotes: 1

Related Questions