How to Create useFetch Hook in React for Data Fetching
To create a
useFetch hook in React, define a function that uses useState and useEffect to fetch data from a URL, manage loading and error states, and return these states. This hook lets components reuse data fetching logic cleanly and reactively.Syntax
The useFetch hook takes a URL string as input and returns an object with data, loading, and error states. It uses useState to store these states and useEffect to trigger the fetch when the URL changes.
- url: The API endpoint to fetch data from.
- data: The fetched data or
nullinitially. - loading: Boolean indicating if the fetch is in progress.
- error: Any error caught during fetch or
null.
javascript
import { useState, useEffect } from 'react'; function useFetch(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { if (!url) return; setLoading(true); setError(null); fetch(url) .then((response) => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then((json) => { setData(json); setLoading(false); }) .catch((err) => { setError(err.message); setLoading(false); }); }, [url]); return { data, loading, error }; }
Example
This example shows how to use the useFetch hook to get user data from a public API and display loading, error, or the user list.
javascript
import React from 'react'; function useFetch(url) { const [data, setData] = React.useState(null); const [loading, setLoading] = React.useState(true); const [error, setError] = React.useState(null); React.useEffect(() => { if (!url) return; setLoading(true); setError(null); fetch(url) .then((response) => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then((json) => { setData(json); setLoading(false); }) .catch((err) => { setError(err.message); setLoading(false); }); }, [url]); return { data, loading, error }; } export default function UserList() { const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/users'); if (loading) return <p>Loading users...</p>; if (error) return <p>Error: {error}</p>; return ( <ul> {data.map(user => ( <li key={user.id}>{user.name} ({user.email})</li> ))} </ul> ); }
Output
<ul><li>Leanne Graham (Sincere@april.biz)</li><li>Ervin Howell (Shanna@melissa.tv)</li><li>Clementine Bauch (Nathan@yesenia.net)</li><li>Patricia Lebsack (Julianne.OConner@kory.org)</li><li>Chelsey Dietrich (Lucio_Hettinger@annie.ca)</li><li>Mrs. Dennis Schulist (Karley_Dach@jasper.info)</li><li>Kurtis Weissnat (Telly.Hoeger@billy.biz)</li><li>Nicholas Runolfsdottir V (Sherwood@rosamond.me)</li><li>Glenna Reichert (Chaim_McDermott@dana.io)</li><li>Clementina DuBuque (Rey.Padberg@karina.biz)</li></ul>
Common Pitfalls
Common mistakes when creating useFetch include not handling cleanup on component unmount, causing memory leaks, or not resetting states when URL changes. Also, forgetting to check response.ok can lead to silent failures.
Always reset loading and error states before fetching new data to avoid stale UI states.
javascript
import { useState, useEffect } from 'react'; // Wrong: No cleanup and no error check function useFetchWrong(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { fetch(url) .then(response => response.json()) .then(json => { setData(json); setLoading(false); }) .catch(err => { setError(err.message); setLoading(false); }); }, [url]); return { data, loading, error }; } // Right: Includes cleanup and error check function useFetchRight(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { if (!url) return; let isMounted = true; setLoading(true); setError(null); fetch(url) .then(response => { if (!response.ok) throw new Error('Network response was not ok'); return response.json(); }) .then(json => { if (isMounted) { setData(json); setLoading(false); } }) .catch(err => { if (isMounted) { setError(err.message); setLoading(false); } }); return () => { isMounted = false; }; }, [url]); return { data, loading, error }; }
Quick Reference
useFetch Hook Cheat Sheet:
url: API endpoint stringdata: fetched data ornullloading:truewhile fetchingerror: error message ornull- Use
useEffectto trigger fetch on URL change - Always check
response.okbefore parsing JSON - Handle cleanup to avoid setting state on unmounted components
Key Takeaways
Create useFetch with useState and useEffect to manage data, loading, and error states.
Always check response.ok to handle HTTP errors properly.
Reset loading and error states before each fetch to keep UI accurate.
Use cleanup in useEffect to prevent memory leaks when components unmount.
Return an object with data, loading, and error for easy use in components.