Creating Custom Hooks in React

Custom hooks in React allow you to extract reusable logic from components into standalone functions. This enables you to share stateful logic across different components without the need for higher-order components or render props.

What is a Custom Hook?

A custom hook is a JavaScript function whose name starts with "use" and may call other hooks if necessary. It typically encapsulates a piece of stateful logic and provides a clean interface for using that logic within functional components.

Example:

import { useState, useEffect } from 'react';

const useFetchData = (url) => {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await fetch(url);
                const result = await response.json();
                setData(result);
                setLoading(false);
            } catch (error) {
                console.error('Error fetching data:', error);
                setLoading(false);
            }
        };

        fetchData();

        return () => {
            // Cleanup function
        };
    }, [url]);

    return { data, loading };
};

In this example, useFetchData is a custom hook that fetches data from a URL and returns the data along with a loading state.

How to Create a Custom Hook

Creating a custom hook involves defining a JavaScript function and using existing hooks within it. Here's how you can create a custom hook:

  1. Define the Hook: Create a JavaScript function whose name starts with "use" to indicate that it's a hook.

  2. Implement the Logic: Write the logic inside the custom hook function, utilizing existing hooks such as useState, useEffect, or other custom hooks if needed.

  3. Return Values: Ensure that the custom hook returns the necessary values, typically state variables or functions.

  4. Use the Hook: Import and use the custom hook in your functional components.

Example Usage:

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

const DataComponent = () => {
    const { data, loading } = useFetchData('https://api.example.com/data');

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

    return (
        <div>
            <h1>Data:</h1>
            <pre>{JSON.stringify(data, null, 2)}</pre>
        </div>
    );
};

export default DataComponent;

Benefits of Custom Hooks

  • Reusability: Custom hooks promote code reuse by encapsulating stateful logic that can be shared across multiple components.

  • Abstraction: They allow you to abstract complex logic into reusable functions, making your components cleaner and easier to understand.

  • Composition: Custom hooks can call other hooks, enabling you to compose multiple hooks together to create more complex behavior.

Custom Hook: useLocalStorage

import { useState, useEffect } from 'react';

const useLocalStorage = (key, initialValue) => {
    const [value, setValue] = useState(() => {
        const storedValue = localStorage.getItem(key);
        return storedValue ? JSON.parse(storedValue) : initialValue;
    });

    useEffect(() => {
        localStorage.setItem(key, JSON.stringify(value));
    }, [key, value]);

    return [value, setValue];
};

The useLocalStorage hook allows you to store and retrieve values from the browser's local storage.

Example Usage:

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

const Counter = () => {
    const [count, setCount] = useLocalStorage('count', 0);

    return (
        <div>
            <h1>Count: {count}</h1>
            <button onClick={() => setCount(count + 1)}>Increment</button>
            <button onClick={() => setCount(count - 1)}>Decrement</button>
        </div>
    );
};

export default Counter;
Info

Custom hooks are a powerful feature in React that enhances code organization and promotes reuse. When creating custom hooks, ensure they have a clear purpose and provide a clean API for consuming components.

However, there are various libraries and repositories that offer collections of custom hooks created by the community. These libraries can be helpful for finding commonly used hooks and reducing boilerplate code in your React projects.

Here are a few popular libraries and resources for custom hooks:

  1. react-use: This is a collection of essential hooks for React developed by streamich. It includes hooks for handling state, side effects, form inputs, and more. You can find it on GitHub: streamich/react-use.

  2. useHooks: This is a website that aggregates a curated list of custom React hooks categorized by functionality. It's a great resource for discovering useful hooks and understanding how they work. You can find it here: usehooks.com.

  3. @rehooks/component-size: This library provides a custom hook for obtaining the size of a React component. It's particularly useful for building responsive layouts. You can find it on npm: @rehooks/component-size.

  4. @use-date-range: This library offers a custom hook for managing date ranges in React applications. It simplifies date range selection and manipulation. You can find it on npm: @use-date-range/core.

Info

While these libraries aren't built into React itself, they provide valuable resources for leveraging custom hooks in your projects. Always ensure that you understand how a custom hook works and verify its suitability for your specific use case before incorporating it into your project.

Task

Practice Creating Custom Hooks

Objective: Create a custom hook that encapsulates reusable logic for handling form inputs and use it in a form component.

  1. Define the Custom Hook:

    Create a new JavaScript file and define a custom hook that manages form state and validation logic.

  2. Implement Form Component:

    Create a form component and use the custom hook to handle form inputs and validation.

  3. Test the Custom Hook:

    Test the custom hook in different scenarios to ensure its correctness and reusability.