Introduction
React hooks are reusable functions. You create them in the same way you create a React component. React hooks serve as a means to separate business logic from component logic. They empower you to create custom hooks that encapsulate certain functionalities, which can then be reused across multiple components. When naming a custom React hook, it's customary to use the prefix use
followed by a descriptive term indicating the action the hook performs. For instance: useFetch
, useDeferredValue
, useDarkMode
, and so on.
Using custom React hooks can make your code:
Readable
Maintainable
Clean
Reusable
Testable
Creating a Custom Hook
Implementing React custom hooks can be intimidating, but I will show you an easy way to break down your component and create a custom React hook.
To do this, we will be using RestCountries to fetch data.
We will use the Countries list API to fetch a list of countries and display the names of the countries on the DOM using our Countries component like this:
import { useEffect, useState } from "react";
export default function Countries() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
let ignore = false;
setLoading(true);
fetch("<https://restcountries.com/v3.1/all>")
.then((data) => data.json())
.then((response) => {
if (!ignore) {
setData(response);
}
})
.catch(() => setData([]))
.finally(() => setLoading(false));
return () => {
ignore = true;
};
}, []);
if (loading) return "Loading...";
return (
<div>
{
data.map((country) => (<div>{country.name.common}</div>))
}
</div>
)
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Countries />);
The next step is to move the business logic from the above component into a hook. This way, when we want to fetch and view the information of a particular country, we can use the hook we created. We will call the hook useFetch
.
import { useEffect, useState } from "react";
export default function useFetch({ url }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
let ignore = false;
setLoading(true);
fetch(url)
.then((data) => data.json())
.then((response) => {
if (!ignore) {
setData(response);
}
})
.catch(() => setError(null))
.finally(() => setLoading(false));
return () => {
ignore = true;
};
}, [url]);
return { data, loading, error };
}
I extended the functionality of the useFetch
hook by adding an error and loading state. This way, you don’t have to worry about creating this everywhere. One optimization is to use just one state for the extra data we are adding to the states but I want this article to be easy for anybody to understand.
Note: you can export the data from a custom react hook using an object literal or an array literal.
return [ data, loading, error ];
// OR
return { data, loading, error };
For this example, we will go with object literals.
Our Countries component will look like this:
import useFetch from "hooks/useFetch";
export default function Countries() {
const { data, loading, error } = useFetch({ url: "<https://restcountries.com/v3.1/all>" });
if (loading)
return (
<div>
<p>Loading...</p>
</div>
);
if (error)
return (
<div>
<p>An error while fetching data</p>
</div>
);
return (
<div>
{
data.map((country) => (<div>{country.name.common}</div>))
}
</div>
)
}
If you want to fetch data from a specific country, all you have to do is create a component and use the useFetch
hook to get the country's data:
const { data, loading, error } = useFetch({ url: "<https://restcountries.com/v3.1/name/aruba>" });
Conclusion
React comes with several built-in hooks like useState
, useReducer
, useContext
. These hooks can do a lot for us as React developers but sometimes, you may need special hooks for special use cases. That’s where custom React hooks come in.
Resources
If you want to learn more about React hooks, you can visit the following pages:
React Documentation: https://react.dev/reference/react
Rooks NPM package: https://www.npmjs.com/package/rooks
useHooks: https://usehooks.com/