Custom useQuery and loading/error states
In this lesson, we'll address how we can handle the loading and error state of our GraphQL queries with our custom useQuery Hook.
📝 This lesson's quiz can be found - here. 🗒️ Solutions for this lesson's quiz can be found - here.
Though our useQuery
Hook works as intended, we haven't taken into account the tracking of the loading and error states of our queries.
Loading#
We'll first address the loading state of our request. When we say loading, we're essentially referring to being able to track the status of our asynchronous request. If the request is in flight, the UI should reflect this with a loading indicator of sorts. And when complete, we should be presented with the expected data.
To keep track of loading, we'll introduce a new loading field into the State
interface of the state object tracked in our custom useQuery
Hook. We'll declare the type of the loading
field as boolean
.
interface State<TData> {
data: TData | null;
loading: boolean;
}
We'll initialize the loading
value as false
in our state initialization.
export const useQuery = <TData = any>(query: string) => {
const [state, setState] = useState<State<TData>>({
data: null,
loading: false
});
// ...
};
At the beginning of the fetchApi()
method within the memoized fetch
callback, we'll set the loading
state to true
while also specifying that our state data
is still null
. When a request is complete we'll set loading
back to false
.
export const useQuery = <TData = any>(query: string) => {
const [state, setState] = useState<State<TData>>({
data: null,
loading: false
});
const fetch = useCallback(() => {
const fetchApi = async () => {
setState({ data: null, loading: true });
const { data } = await server.fetch<TData>({
query
});
setState({ data, loading: false });
};