Custom useQuery and refetch
In this lesson, we'll introduce the capability for a component to manually refetch a query from the useQuery Hook.
📝 This lesson's quiz can be found - here. 🗒️ Solutions for this lesson's quiz can be found - here. 📃 Grab a cheatsheet describing how React's
useCallback
Hook can be used - here.
Our custom useQuery
Hook made our <Listings>
component simpler and provided the opportunity to have the shared piece of functionality of querying and updating state with other components as well.
In this lesson, we'll address how we'd like a query refetch be made when the deleteListing
mutation is fired. We'll have our useQuery
Hook prepared to allow for a component to trigger a refetch.
Gameplan#
There might be a few ways we can think about solving this but a simple way we'd like to go with is we can perhaps destruct the fetchApi()
function from our useQuery
Hook and have it labeled as refetch()
. If we ever intend to refetch the query stated in the Hook, we can simply run this function directly in our component.
export const Listings = ({ title }: Props) => {
const { data, refetch } = useQuery<ListingsData>(LISTINGS);
const deleteListing = async (id: string) => {
// ...
refetch();
};
// ...
};
refetch()
#
The fetchApi()
function in our useQuery
Hook is the function we'll want to run again if we needed to refetch query information and update state. In the useQuery.ts
file, we'll restructure how our Hook is set up to have the fetchApi()
function be returned from the Hook. To do so, we'll need to declare the fetchApi()
function outside of the effect callback.
import { useState, useEffect } from "react";
import { server } from "./server";
interface State<TData> {
data: TData | null;
}
export const useQuery = <TData = any>(query: string) => {
const [state, setState] = useState<State<TData>>({
data: null
});
const fetchApi = async () => {
const { data } = await server.fetch<TData>({
query
});
setState({ data });
};
useEffect(() => {
fetchApi();
}, [query]);
return { state, refetch: fetchApi };
};
In the return
statement of our useQuery
Hook, we return an object that contains all the properties within state by using the JavaScript spread syntax to expand the properties of state in the new object. We've also introduced a new property called refetch
that has the value of the fetchApi()
function.
ESLint will display a warning in the useEffect
dependencies list stating that the useEffect
Hook is missing the dependency - fetchApi
.

If we attempt to place fetchApi
has a dependency to the useEffect
Hook, we'll get another ESLint warning telling us the fetchApi
dependency will make the dependencies of useEffect
run on every render which is not what we want.

This is where we can follow the suggestion given to us from the react-hooks/exhaustive-deps
ESLint rule to wrap the fetchApi()
function within a useCallback
Hook.
useCallback()
#
We'll import the useCallback
Hook in our useQuery.ts
file.
import { useState, useEffect, useCallback } from "react";
The useCallback