React Custom Hooks

Introduction

In this chapter, we will explore how to create custom hooks in React. Custom hooks allow you to encapsulate reusable logic and stateful behavior in a function that can be shared across multiple components. This can help you write cleaner and more maintainable code. We will create a new React project from scratch, explain the syntax of custom hooks, and walk through a real-time project step by step to demonstrate their usage.

Table of Contents

  1. Setting Up a New React Project
  2. What are Custom Hooks?
  3. Creating a Custom Hook
    • Project Setup
    • Creating a useFetch Hook
    • Using useFetch in a Component
  4. Real-Time Project: Employee Management System with Custom Hooks
    • Project Setup
    • Creating the useEmployeeData Hook
    • Using useEmployeeData in the Employee Component
  5. Conclusion

Setting Up a New React Project

First, let’s create a new React project using the create-react-app tool.

  1. Open your terminal and run the following command:

    npx create-react-app custom-hooks-employee-app
    
  2. Navigate to the project directory:

    cd custom-hooks-employee-app
    

What are Custom Hooks?

Custom hooks are JavaScript functions that start with the word "use" and can call other hooks. They allow you to extract and reuse logic and stateful behavior in a way that is easy to share across multiple components.

Example

Here’s a simple example of a custom hook that logs a message when a component mounts and unmounts:

import { useEffect } from 'react';

function useLogger(message) {
  useEffect(() => {
    console.log(message);
    return () => {
      console.log(`Cleanup: ${message}`);
    };
  }, [message]);
}

export default useLogger;

You can use this custom hook in any component:

import React from 'react';
import useLogger from './useLogger';

function MyComponent() {
  useLogger('MyComponent mounted');

  return <div>MyComponent</div>;
}

export default MyComponent;

Creating a Custom Hook

Project Setup

  1. Open the project directory in your code editor.

  2. Remove the default content from src/App.js and src/App.css:

    // src/App.js
    import React from 'react';
    import './App.css';
    import Employee from './Employee';
    
    function App() {
      return (
        <div className="App">
          <h1>Employee Management System</h1>
          <Employee />
        </div>
      );
    }
    
    export default App;
    
    /* src/App.css */
    .App {
      text-align: center;
      padding: 20px;
    }
    
    h1 {
      margin-bottom: 20px;
    }
    

Creating a useFetch Hook

  1. Create a new file named useFetch.js in the src directory.

  2. Define the useFetch hook:

    // src/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(() => {
        fetch(url)
          .then((response) => {
            if (!response.ok) {
              throw new Error('Network response was not ok');
            }
            return response.json();
          })
          .then((data) => {
            setData(data);
            setLoading(false);
          })
          .catch((error) => {
            setError(error);
            setLoading(false);
          });
      }, [url]);
    
      return { data, loading, error };
    }
    
    export default useFetch;
    

    Explanation:

    • The useFetch hook takes a URL as an argument and fetches data from that URL.
    • It returns an object containing data, loading, and error states.

Using useFetch in a Component

  1. Create a new file named Employee.js in the src directory.

  2. Define the Employee component:

    // src/Employee.js
    import React from 'react';
    import useFetch from './useFetch';
    import './Employee.css';
    
    function Employee() {
      const { data: employees, loading, error } = useFetch('https://jsonplaceholder.typicode.com/users');
    
      if (loading) return <p>Loading...</p>;
      if (error) return <p>Error: {error.message}</p>;
    
      return (
        <div className="container mt-5">
          <ul className="list-group">
            {employees.map((employee) => (
              <li key={employee.id} className="list-group-item">
                {employee.id} - {employee.name} ({employee.email})
              </li>
            ))}
          </ul>
        </div>
      );
    }
    
    export default Employee;
    

    Explanation:

    • The Employee component uses the useFetch hook to fetch employee data from an API.
    • It handles the loading and error states and displays the employee data in a list.
  3. Create a CSS file named Employee.css to style the Employee component:

    /* src/Employee.css */
    .container {
      max-width: 600px;
      margin: 0 auto;
      text-align: left;
    }
    
    .list-group-item {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 10px;
      border: 1px solid #ccc;
      border-radius: 4px;
      margin-bottom: 10px;
    }
    

Real-Time Project: Employee Management System with Custom Hooks

Project Setup

  1. Ensure the project is set up as previously described.

Creating the useEmployeeData Hook

  1. Create a new file named useEmployeeData.js in the src directory.

  2. Define the useEmployeeData hook:

    // src/useEmployeeData.js
    import { useState, useEffect } from 'react';
    
    function useEmployeeData(url) {
      const [employees, setEmployees] = useState([]);
      const [loading, setLoading] = useState(true);
      const [error, setError] = useState(null);
    
      useEffect(() => {
        fetch(url)
          .then((response) => {
            if (!response.ok) {
              throw new Error('Network response was not ok');
            }
            return response.json();
          })
          .then((data) => {
            setEmployees(data);
            setLoading(false);
          })
          .catch((error) => {
            setError(error);
            setLoading(false);
          });
      }, [url]);
    
      return { employees, loading, error };
    }
    
    export default useEmployeeData;
    

    Explanation:

    • The useEmployeeData hook takes a URL as an argument and fetches employee data from that URL.
    • It returns an object containing employees, loading, and error states.

Using useEmployeeData in the Employee Component

  1. Modify the Employee component to use the useEmployeeData hook:

    // src/Employee.js
    import React from 'react';
    import useEmployeeData from './useEmployeeData';
    import './Employee.css';
    
    function Employee() {
      const { employees, loading, error } = useEmployeeData('https://jsonplaceholder.typicode.com/users');
    
      if (loading) return <p>Loading...</p>;
      if (error) return <p>Error: {error.message}</p>;
    
      return (
        <div className="container mt-5">
          <ul className="list-group">
            {employees.map((employee) => (
              <li key={employee.id} className="list-group-item">
                {employee.id} - {employee.name} ({employee.email})
              </li>
            ))}
          </ul>
        </div>
      );
    }
    
    export default Employee;
    

    Explanation:

    • The Employee component now uses the useEmployeeData hook to fetch employee data.
    • This makes the component cleaner and more focused on rendering, while the data fetching logic is encapsulated in the custom hook.

Conclusion

In this chapter, we created a new React project and explored custom hooks. We learned what custom hooks are and how to create them. We walked through a real-time project step by step, creating a useFetch hook and a useEmployeeData hook to fetch and manage employee data. By understanding and using custom hooks, you can encapsulate reusable logic and stateful behavior, making your React applications cleaner and more maintainable.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top