useFetch hook in React

February 23, 2023 (1y ago)

In this article, we'll show you how to create a custom useFetch hook in React that you can use to fetch data from an API using both GET and POST methods.

  • Import the necessary libraries

To get started, we'll need to import the useState and useEffect hooks from the react library.

import { useState, useEffect } from "react"
  • Create the useFetch hook

Next, we'll create our useFetch hook. This hook will take a URL as an argument, along with a method (either 'GET' or 'POST'), and optional body data for POST requests. It will return an object that contains the fetched data, as well as a loading state and any errors that occur.

import { useState } from "react"

export default function useFetch(baseUrl) {
	const [loading, setLoading] = useState(true)

	function get(url) {
		return new Promise((resolve, reject) => {
			fetch(baseUrl + url)
				.then((response) => response.json())
				.then((data) => {
					if (!data) {
						setLoading(false)
						return reject(data)
					}
					setLoading(false)
					resolve(data)
				})
				.catch((error) => {
					setLoading(false)
					reject(error)
				})
		})
	}

	function post(url, body) {
		return new Promise((resolve, reject) => {
			fetch(baseUrl + url, {
				method: "post",
				headers: {
					"Content-Type": "application/json",
				},
				body: JSON.stringify(body),
			})
				.then((response) => response.json())
				.then((data) => {
					if (!data) {
						setLoading(false)
						return reject(data)
					}
					setLoading(false)
					resolve(data)
				})
				.catch((error) => {
					setLoading(false)
					reject(error)
				})
		})
	}

	return { get, post, loading }
}
  • Use the useFetch hook

Now that we've created our useFetch hook, we can use it in our components to fetch data from an API using both GET and POST methods.

Get example

import { useEffect, useState } from "react"
import Product from "./Product.js"
import Loader from "./Loader.js"
import useFetch from "./useFetch.js"

export default function StoreFront() {
	const [details, setDetails] = useState([])
	const { get, loading } = useFetch("https://api.example.com/")

	useEffect(() => {
		get("products.json")
			.then((data) => {
				console.log(data)
				setDetails(data)
			})
			.catch((error) => console.error(error))
	}, [])

	if (loading) {
		return <Loader />
	}

	return (
		<div className="store-front">
			{details &&
				details.map((item) => <Product key={item.id} {...item} />)}
		</div>
	)
}

POST example

import { useState } from "react"
import ProductsList from "./ProductsList.js"
import AddProductForm from "./AddProductForm.js"
import useFetch from "./useFetch.js"

export default function StoreFront() {
	const [products, setProducts] = useState([])
	const [name, setName] = useState("")
	const [description, setDescription] = useState("")
	const [validation, setValidation] = useState("")
	const { post } = useFetch("https://api.example.com/products/")

	function handleFormSubmit(event) {
		event.preventDefault()

		if (!name) {
			setValidation("Please enter a name")
			return
		}
		if (!description) {
			setValidation("Please enter a description")
			return
		}
		post("products", {
			name: name,
			description: description,
		})
			.then((data) => {
				console.log(data)
				if (data) {
					setProducts([
						...products,
						{
							id: products.length + 1,
							name: name,
							description: description,
						},
					])
					setName("")
					setDescription("")
					setValidation("")
				}
			})
			.catch((error) => console.log(error))
	}

	function handleNameChange(event) {
		setName(event.target.value)
	}

	function handleDescriptionChange(event) {
		setDescription(event.target.value)
	}

	function handleDeleteClick(id) {
		setProducts(products.filter((product) => product.id !== id))
	}

	return (
		<>
			<AddProductForm
				name={name}
				description={description}
				validation={validation}
				onNameChange={handleNameChange}
				onDescriptionChange={handleDescriptionChange}
				onFormSubmit={handleFormSubmit}
			/>
			<div>{products.length === 0 && <p>Add your first product</p>}</div>
			<ProductsList
				products={products}
				onDeleteClick={handleDeleteClick}
			/>
		</>
	)
}

In this example, we've used the useFetch hook to make a GET and POST request to https://api.example.com/products. We've then used the loading and error states to display a loading message or an error message, respectively. Finally, we've displayed the fetched data in our component.

And that's it! You now have a custom useFetch hook that you can use in your React applications to fetch data from an API using both GET and POST methods.

- Design and development by me.

@2024