This article is about creating your own React Hooks to perform async operations. As an example, we will create a custom useFetch Hook to make API calls.
Hooks are functions which let you use state and other React features without writing a class. They are a new addition in React 16.8. You can check the overview of Hooks before moving ahead. One important thing about Hooks is that they can only be used either in a functional component or inside another Hook.
A custom Hook allows you to extract some components logic into a reusable function. It is a reusable JavaScript function that can call other Hooks.
Hooks are JavaScript functions, but they impose two additional rules:
- Only call Hooks at the top level. Don't call Hooks inside loops, conditions, or nested functions.
- Only call Hooks from React function components. Don't call Hooks from regular JavaScript functions.
There are no bounds to the functionality that you can achieve using Hooks. But, in this article, we are just creating a specific type of custom Hook to perform async operations (API calls in this example) and tailor it to fit our use-cases. We will also have a function fetchNow that can be used to fetch the data with a callback. This should be the basic API for our example Hook.
const { data, loading, error } = useFetch("https://www.reddit.com/r/popular.json");
Alternative API could be the following.
const { data, loading, error, fetchNow } = useFetch();
We will start with creating our Hook and we will name it useFetch. It takes url and options as parameters. We will use useState and useEffect Hooks internally to implement our Hook.
function useFetch(url: string, options?: any) {const [data, setData] = useState();const [loading, setLoading] = useState(false);const [error, setError] = useState();function fetchNow(url: string, options?: any) {// we will add the code here}useEffect(() => {fetchNow(url, options);}, []);return { data, loading, error, fetchNow };}
To prevent the extra re-renders. We will merge our setState Hooks.
function useFetch(url: string, options?: any) {const [status, setStatus] = useState<{loading: boolean;error?: Error;data?: any;}>({loading: false});function fetchNow(url: string, options?: any) {// we will add the code here}useEffect(() => {fetchNow(url, options);}, []);return { ...status, fetchNow };}
Now, we have the bare-bones of our Hook ready. You can add the code according to the functionality of the Hook you are creating. In our case, we need to add the API calls. We will use the fetch API for this. After adding the logic, our function looks like this.
function useFetch(url?: string, options?: any) {const [status, setStatus] = useState<{loading: boolean;error?: Error;data?: any;}>({loading: false});function fetchNow(url: string, options?: any) {setStatus({ loading: true });fetch(url, options).then((res: any) => res.json()).then((res: any) => {setStatus({ loading: false, data: res.data });}).catch((error: Error) => {setStatus({ loading: false, error });});}useEffect(() => {if (url) {fetchNow(url, options);}}, []);return { ...status, fetchNow };}
The function is complete now. We will use them in our functional component like the initially expected API or with a callback like in the code shown below. And we will get the fetched data status in the variables named data, loading, error.
<button onClick={() => fetchNow("https://www.reddit.com/r/popular.json")}>Fetch data</button>
You can check the sandbox below for the complete functionality of Hook.
This is just one of the common use-cases of custom hooks. You can achieve a lot of great things with them. You got the idea on how to create custom Hooks. Here, we just made the API calls inside the Hook, but you can do all sorts of async operations using the same idea.
Thanks for reading. Hope you found it helpful! Happy coding!
Views 23408
Discuss on Twitter