Skip to content
Advertisement

How to use a custom React hook to make a POST or DELETE request with Axios

I am trying to make a generic useAxios hook in React. I would like to be able to import this hook into other components to make Get, Post, and Delete requests. I have created the hook and it works fine for making Get requests, but I am stuck on how to make it work for Post/Delete requests.

The issue is that I would be making the Post/Delete request when a user clicks a Save or Delete button, but I cannot call a React hook from an event handler function or from useEffect.

Below is the generic hook I created:

import { useState, useEffect } from "react";
import axios from "axios";

export interface AxiosConfig<D> {
    method?: 'get' | 'post' | 'delete' | 'put';
    url: string;
    data?: D;
    params?: URLSearchParams;
}

export const useAxios = <T, D = undefined >(config: AxiosConfig<D>) => {
    
    const [responseData, setResponseData] = useState<T>();
    const [isLoading, setIsloading] = useState(true);
    const [isError, setIsError] = useState(false);

    useEffect(() => {
        const controller = new AbortController();
        const axiosRequest = async () => {
            try {
                const response = await axios({ ...config, signal: controller.signal })
                setResponseData(response.data)
                setIsloading(false);
            } catch (error) {

                setIsError(true);
                setIsloading(false);
            }
        }

        axiosRequest();

        return () => {
            controller.abort();
        }
    }, [config.url, config.method, config.data, config.params])

    return {responseData, isLoading, isError}
}

And this is an example of a component where I would like to make a Delete request

import { useParams } from 'react-router';
import { useAxios } from '../../api/hooks/useAxios';

export interface IItem {
    title: string;
    info: string;
}

export default function Item() {
    const { id } = useParams<{id?: string}>();

    const {responseData: item, isLoading, isError} = useAxios<IItem>({
        method: 'get',
        url: `http://localhost:3000/items/${id}`
    })

    const handleDelete = () => {
        //not sure what to do here. Need to make DELETE request

    }

    return (
        <div>
            {isLoading && <p className='loading'>Loading...</p>}
            {isError && <p className='error'>Could Not Load Item</p>}
            {item && (
                <>
                    <h2>{item.title}</h2>
                    <p>{item.info}</p>
                    <button onClick={handleDelete}>Delete</button>
                </>
            )}
        </div>
    )
}

I could just make the axios request directly in the Item component and not use my useAxios hook, but then I would end up repeating code throughout the application.

Advertisement

Answer

Assuming your DELETE route is the same as the GET route, you’d just store the method type in a local state variable and change it:

const { id } = useParams<{id?: string}>();
const [method, setMethod] = useState('get');

const {responseData: item, isLoading, isError} = useAxios<IItem>({
  method,
  url: `http://localhost:3000/items/${id}`
});

const handleDelete = () => setMethod('delete');

However, I think you will realize that this only solves part of the problem, which is that you have tightly coupled your component’s return JSX with the response type of the GET request (IItem).

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement