Creating a custom hook for fetching data in your React applications
Stop re-writing the same fetch code in all your components
Table of contents
Creating a simple hook to handle API data in your React applications
Intro
In this post we are going to explore custom hooks in React and then build one to fetch data from an API.
πͺ What are custom hooks in React?
Most simply, and directly from the React docs,
"Building your own Hooks lets you extract component logic into reusable functions."
For our example letβs say that our app has some data to fetch from an API. We could copy and paste some fetch logic into our components wherever we need to retrieve data but it wouldnβt be ideal. Custom hooks allow us to remove duplicated logic from our components. That way, once weβve extracted the logic to a custom hook, we can just use it!
For example, the useAPI hook we're creating today can fetch quotes from the beloved "Parks and Recreation" character Ron Swanson and displaying them as a heading element like so π
Then in a separate component we could use the same hook to call another API route without needing to rewrite much code π
π Important to remember about React hooks π
You have to name custom Hooks starting with βuseβ.
This convention is very important. Without it, React canβt automatically check for violations of Hook rules because it can't tell if a certain function contains calls to Hooks inside of it.
Two components using the same Hook DO NOT share state.
Custom Hooks are a mechanism to reuse stateful logic (such as setting up a subscription and remembering the current value), but every time you use a custom Hook, all state and effects inside of it are fully isolated.
Fetching & Displaying Data Without Hooks
One of the most common things we need to do in our applications is to grab data from a server. On top of that, while it is being fetched from the server, we also need to show the user a loading screen. This logic we will generally need again at various other places in the app.
Generally when fetching some data from an API endpoint we will:
- Show a loading screen/component.
- Call an API.
- Receive some data.
- Stop loading.
- Render/use that data.
// App.js
import { useEffect, useState } from "react"
const App = () => {
const [loading, setLoading] = useState(true)
const [data, setData] = useState(null)
const fetchApi = () => {
fetch('https://ron-swanson-quotes.herokuapp.com/v2/quotes')
.then(response => {
return response.json()
})
.then(json => {
console.log(json)
setLoading(false)
setData(json)
})
};
useEffect(() => {
fetchApi();
}, []);
if(loading) return <h1>Loading</h1>
return <div>
<h1>Data fetched successfully.</h1>
{JSON.stringify(data)}
</div>
};
export default App;
πͺ Now Fetching & Displaying Data With Our Custom useAPI Hook
Extracting the fetch logic to a custom hook allows us to reuse it easily in all of our other components and greatly reduces the lines of code our components need to consume data. In this case we got rid of almost half the code in our ./app.js
file π
import Loading from '../components/Loading';
import useAPI from '../lib/hooks/useAPI';
export default function App() {
const {loading, data, error} = useAPI('/api/hello')
if (error) {
return (<p>{JSON.stringify(error, null, 2)}</p>)
}
else {
return (
loading === true
? <Loading />
: <h2>{JSON.stringify(data)}</h2>
)
}
}
Writing our hook πͺ
To keep things organized we'll create a directory to house our custom hooks ./lib/hooks
and we'll create our useApi hook under the file name ./lib/hooks/useAPI.js
.
Breakdown of our hook
We'll get in the basic bones of our hook first. Where we create and export our "use" function and determine the state it will be returning. (Below) You can see we're creating a "useAPI" function that will return {loading, data, error}
import axios from 'axios';
import { useEffect, useState } from 'react';
const useAPI = (path) => {
const [loading, setLoading] = useState(true);
const [data, setData] = useState(null);
const [error, setError] = useState(null);
return {
loading,
data,
error
};
};
export default useAPI;
Making the call π
Now we add a makeCall()
function and use that to set the {loading, data, error}
state in our hook, and then call that function in a React.useEffect
with an empty dependency array. The makeCall()
function we add will set our state variables for our hook to return, and that's our custom hook!
The Whole Hook
Wrapping Up
Custom hooks allow us to extract our common component logic into reusable functions, and we can write them to do just about anything. In our case we created a "useAPI" hook to consume data plus handle loading and errors.
You can find the code for this hook here
gist.github.com/MiCurran/6d13...
THANKS FOR READING! π