React/ReactJS: Custom Hooks

Before Hooks, Render Props and Higher-Order Components are the two ways state is shared between components in React.

However, logic between two functions is better shared by extracting it to a third function. It works both for Function Components and Hooks as they are functions.

A Custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks.

Below we construct a simple Custom Hook called usePi.js which uses the two built-in Hooks useState and useEffect and returns the value of π. It is, of course, practically a useless example.

Following the Rules of Hook, we call the existing Hooks at the top level even inside a Custom Hook. They are not to be called inside loops, conditions, or nested functions. They are also not to be called from regular JavaScript functions.

We pass an empty array [] as the second argument to useEffect, which serves the purpose of componentDidMount(), signalling that it is called only once after the component is mounted.

				// usePi.js
				import { useState, useEffect } from "react";

				const usePi = () => {
				  const [pi, setPi] = useState(0);

				   useEffect(() => {
				  }, []);

				  return pi;

				export default usePi;

We import and use the above Custom Hook usePi.js inside a function component:

				import React from "react";
				import usePi from "./usePi";

				const valueOfPi = (props) => {
				  const pi = usePi();

				  return (
				      The value of pi is {pi}

				export default valueOfPi;
reactjs custom hooks usepi

Practically, we need not go about in such roundabout manner (to the extent of creating Custom Hooks) just to get the value of π.

We pick a much useful example in the section below.

The useFetch() Custom Hook

Now we will take up a different example, something useful practically compared to the first above. We build a Custom Hook to fetch some data on load of a component using the Fetch API. We pass an empty array [] to useEffect() indicating that it is a one-time load on initiation of the component.

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

					const useFetch = (url) => {
					  const [data, setData] = useState([]);

					  useEffect(() => {
					      .then(response => response.json())
					      .then(data => setData(data));
					  }, []);

					  return data;

					export default useFetch;

Now we will use the above Custom Hook we just created in another component. We fetch a random Chuck Norris joke by passing the free URL into our usefetch() custom hook, which retrieves the following JSON:

					    "categories": [
					    "created_at": "2020-01-05 13:42:19.324003",
					    "icon_url": "",
					    "id": "fivi0z5lt8gp_6vt3cc8pw",
					    "updated_at": "2020-01-05 13:42:19.324003",
					    "url": "",
					    "value": "If Chuck Norris writes code with bugs, the bugs fix themselves."

And inside another component, we just render the icon_url and value fields.

					import React from "react";
					import useFetch from "./useFetch";

					const ChuckNorrisJoke = () => {
					  const data = useFetch("");
					  return (
					      <img src={data.icon_url}/>

					export default ChuckNorrisJoke;

The output is as follows.

reactjs custom hooks chuck norris joke

NOTE. If you refresh the page, the joke will change.