Reusable React-Query Hooks with Typescript: Simplifying API Calls

Deshan Madurajith
2 min readFeb 11, 2023

--

In this blog post, we will delve into the power of reusable hooks in combination with React-Query and Typescript to streamline API calls in React applications.

Writing all the API calls in one place not only keeps the code organized but also allows for full utilization of the capabilities of React-Query. With the added bonus of being type-safe and straightforward, this approach to handling API calls is both efficient and effective

import {
QueryOptions,
useMutation,
UseMutationOptions,
useQuery,
UseQueryOptions,
} from '@tanstack/react-query';
import axios from 'axios';

// Note: Move to new file. Ex: types/api.types.ts
export type ApiServiceErr = any;
export type MutOpt<Response, TVariables = unknown> = UseMutationOptions<
Response,
ApiServiceErr,
TVariables,
unknown
>;
export type QueryOpt<Response, TVariables = unknown> = UseQueryOptions<
Response,
ApiServiceErr,
TVariables,
any[]
>;
interface ParamOptions {
limit: number;
page: number;
sortBy: string;
}

// Note: Move to a new file. Ex: types/user.types.ts
interface BaseUser {
id: string;
name: string;
email: string;
role: string;
createdAt: string;
updatedAt: string;
}

// Note: Move to a new file. Ex: api/user.ts
type UserResponse = BaseUser;
type UpdateUserBody = Pick<BaseUser, 'id' | 'name' | 'email'>;

export const useUpdateUser = (opt?: MutOpt<UserResponse>) =>
useMutation<UserResponse, ApiServiceErr, UpdateUserBody>(async (data) => {
const response = await axios.put(`/users/update`, data);
return response.data;
}, opt);

export const useGetUsers = (
{ limit, page, sortBy }: ParamOptions,
opt?: QueryOptions<UserResponse[]>,
) =>
useQuery<UserResponse[], ApiServiceErr>(
[limit, page, sortBy],
async () => {
const response = await axios.get(
`/users/paginate/users?limit=${limit}&page=${page}&sortby=${sortBy}`,
);
return response.data;
},
opt,
);

Now you can use this in the component. You don’t need to introduce many variables for errors and success. You can use the events. You can show those errors and success messages in a nice alert box (ex: https://react-hot-toast.com/)

 
// In the component
export const UsersPage = () => {

const { data, isLoading, refetch } = useGetUsers(
{ limit, page, sortBy},
{ onError: (err) => console.log(err) },
);

const { mutate: updateUser, isLoading: isUpdatingUser } = useUpdateUser({
onSuccess: () => console.log(err),
onError: (err) => console.log(err),
});

...
...

return (<>...</>)
}

I hope this might helpful for you. Let me know your feedback!

--

--

Deshan Madurajith

Software Engineer (Typescript, NodeJs, React & React Native)