Skip to main content

The Power of Custom Hooks: Why They Are a Game-Changer for React #81

📖 Introduction

Following our exploration of advanced form handling, this article introduces a concept that is fundamental to modern React development: Custom Hooks. We will learn what custom hooks are, why they are so powerful, and how they can help us write cleaner, more reusable, and more maintainable code.


📚 Prerequisites

Before we begin, please ensure you have a solid grasp of the following concepts:

  • React Hooks, especially useState and useEffect.
  • Functional components.

🎯 Article Outline: What You'll Master

In this article, you will learn:

  • The "Why" of Custom Hooks: Understanding the problems custom hooks solve and why they are a core feature of modern React.
  • The Rules of Custom Hooks: The two simple rules you must follow when creating your own hooks.
  • Core Implementation: How to create your first custom hook.
  • Practical Application: How to use a custom hook in a component.

🧠 Section 1: The Core Concepts of Custom Hooks

Before hooks were introduced in React 16.8, sharing stateful logic between components was a challenge. The common patterns were render props and higher-order components (HOCs), which could lead to complex and deeply nested component trees (often referred to as "wrapper hell").

Custom hooks solve this problem by allowing you to extract component logic into reusable functions.

A custom hook is simply a JavaScript function whose name starts with use and that can call other hooks. That's it. There's nothing special about them beyond this convention.

The two rules of hooks:

  1. Only call hooks at the top level: Don't call hooks inside loops, conditions, or nested functions.
  2. Only call hooks from React functions: Call hooks from React functional components and not from regular JavaScript functions. A custom hook is considered a "React function".

💻 Section 2: Deep Dive - Creating Your First Custom Hook

Let's create a simple custom hook to see how they work. A common piece of logic that is often repeated in components is fetching data from an API. Let's create a useFetch hook to handle this.

2.1 - The useFetch Hook

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

function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const json = await response.json();
setData(json);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};

fetchData();
}, [url]);

return { data, loading, error };
}

export default useFetch;

Step-by-Step Code Breakdown:

  1. function useFetch(url) { ... }: We define a function called useFetch that takes a url as an argument.
  2. useState: We use the useState hook to manage the data, loading, and error states.
  3. useEffect: We use the useEffect hook to fetch the data when the component mounts or the url changes.
  4. return { data, loading, error };: We return an object with the data, loading, and error states.

2.2 - Using the useFetch Hook

Now, let's use our useFetch hook in a component.

// MyComponent.js
import React from 'react';
import useFetch from './useFetch';

function MyComponent() {
const { data, loading, error } = useFetch('https://api.example.com/data');

if (loading) {
return <div>Loading...</div>;
}

if (error) {
return <div>Error: {error.message}</div>;
}

return (
<div>
{/* Render your data here */}
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}

export default MyComponent;

Code Breakdown:

  1. import useFetch from './useFetch';: We import our custom hook.
  2. const { data, loading, error } = useFetch('https://api.example.com/data');: We call our custom hook with the URL we want to fetch.
  3. We then use the data, loading, and error states to render our component.

As you can see, our component is now much cleaner and more focused on rendering the UI. All the logic for fetching data is encapsulated in the useFetch hook, which can be reused in any other component that needs to fetch data.


💡 Conclusion & Key Takeaways

In this article, we've been introduced to the power of custom hooks. We've seen how they can be used to extract and reuse stateful logic, leading to cleaner and more maintainable code.

Let's summarize the key takeaways:

  • Custom hooks are reusable functions that allow you to share stateful logic between components.
  • They must start with the word use and can call other hooks.
  • They help to keep your components clean and focused on their rendering responsibilities.

Challenge Yourself: To solidify your understanding, try to create a useLocalStorage hook that allows you to store and retrieve data from the browser's local storage.


➡️ Next Steps

You now have a basic understanding of custom hooks. In the next article, "Creating Your First Custom Hook: useToggle (Part 1)", we will walk through the process of creating another simple and practical custom hook from scratch.

Thank you for your dedication. Stay curious, and happy coding!


glossary

  • Custom Hook: A JavaScript function whose name starts with use and that can call other hooks.
  • Render Props: A technique for sharing code between React components using a prop whose value is a function.
  • Higher-Order Component (HOC): A function that takes a component and returns a new component.

Further Reading