Module 7 Summary
This lesson is a summary of the work done in Module 7.0.
In this module, we've introduced a few different Hooks to allow us to manipulate and handle information in our <Listings>
component. By the end of the module, we created and used the custom Hooks, useQuery
and useMutation
.
useQuery
#
The useQuery
Hook is responsible for consolidating the information in having a GraphQL query be run the moment the component mounts. It returns a series of information such as the data that is to be returned from a query as well as the loading
and error
status of the query request. It also returns a refetch
property which allows components to refetch a query whenever the component may want to.
To keep track of the state of information within our query, we used React's useReducer
Hook. Initially, we used the useState
Hook which allows us to add React state to functional components. We moved to use the useReducer
Hook to get a clearer separation between updates to the state object and actions needed to update the state object.
The useEffect
Hook is used to invoke the query request the moment the component mounts. To be able to extract the function needed to make the request outside of the useEffect
Hook, we used the useCallback
Hook to memoize the fetch()
function to never run until the query
parameter value is changed. query
is unlikely to ever change since it's to be a constant value declared outside of components.
import { useReducer, useEffect, useCallback } from "react";
import { server } from "./server";
interface State<TData> {
data: TData | null;
loading: boolean;
error: boolean;
}
interface QueryResult<TData> extends State<TData> {
refetch: () => void;
}
type Action<TData> =
| { type: "FETCH" }
| { type: "FETCH_SUCCESS"; payload: TData }
| { type: "FETCH_ERROR" };
const reducer = <TData>() => (
state: State<TData>,
action: Action<TData>
): State<TData> => {
switch (action.type) {
case "FETCH":
return { state, loading: true };
case "FETCH_SUCCESS":
return { state, data: action.payload, loading: false, error: false };
case "FETCH_ERROR":
return { state, loading: false, error: true };
default:
throw new Error();
}
};
export const useQuery = <TData = any>(query: string): QueryResult<TData> => {
const fetchReducer = reducer<TData>();
const [state, dispatch] = useReducer(fetchReducer, {
data: null,
loading: false,
error: false
});
const fetch = useCallback(() => {
const fetchApi = async () => {
try {
dispatch({ type: "FETCH" });
const { data, errors } = await server.fetch<TData>({
query
});
if (errors && errors.length) {
throw new Error();
}
dispatch({ type: "FETCH_SUCCESS", payload: data });
} catch {
dispatch({ type: "FETCH_ERROR" });
}
};
fetchApi();
}, [query]);
useEffect(() => {
fetch();
}, [fetch]);
return { state, refetch: fetch };
};
useMutation
#
The useMutation
Hook is similar to the useQuery
Hook except for where a useEffect
Hook isn't used to make the GraphQL request when the component first mounts.
This page is a preview of TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL