DEV Community

Harshit Singh
Harshit Singh

Posted on

Custom Hooks in React: A Guide to Creation and Usage

React’s built-in hooks are powerful, but sometimes we encounter scenarios that require shared logic across multiple components. That’s where custom hooks come in! They allow us to abstract reusable logic into a function that utilizes React hooks. Here’s everything you need to know about creating and using custom hooks.


What Are Custom Hooks?
Custom hooks are JavaScript functions that:

  • Start with the prefix use (e.g., useMyCustomLogic).
  • Encapsulate and reuse logic that involves one or more built-in React hooks.

They make your code cleaner, more modular, and easier to maintain.


Why Create Custom Hooks?

  1. Reusability : Avoid duplicating logic across multiple components.
  2. Separation of Concerns : Keep your component code focused on rendering, moving business logic into a custom hook.
  3. Improved Readability : Makes components easier to understand by offloading complex operations.
  4. Testability : Hooks are easier to test than testing the logic embedded within components.

How to Create a Custom Hook Step-by-Step Example: useWindowSize**
Let's create a hook that tracks the window's width and height.

  1. Import Necessary Built-in Hooks :
import { useState, useEffect } from 'react';

Enter fullscreen mode Exit fullscreen mode
  1. Define the Custom Hook :
function useWindowSize() {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    // Handler to update window size
    const handleResize = () => {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    // Attach the event listener
    window.addEventListener('resize', handleResize);

    // Cleanup listener on unmount
    return () => window.removeEventListener('resize', handleResize);
  }, []); // Empty dependency array ensures this runs once on mount

  return windowSize;
}

Enter fullscreen mode Exit fullscreen mode
  1. Use Your Hook in a Component :
function App() {
  const { width, height } = useWindowSize();

  return (
    <div>
      <h1>Window Size</h1>
      <p>Width: {width}px</p>
      <p>Height: {height}px</p>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Key Guidelines for Custom Hooks

  1. Naming : Always start the function name with use. This convention ensures React recognizes it as a hook and validates its usage.
  2. Hook Rules : Custom hooks must follow the Rules of Hooks , i.e., they:
  3. Can only be called at the top level of a function.
  4. Can only be used within React functional components or other custom hooks.
  5. Return What You Need : Custom hooks can return:
  6. A value (e.g., a state variable).
  7. An object (e.g., multiple states and functions).
  8. A function (e.g., useCounter returning increment and decrement functions).

Advanced Example: useFetch**
Here’s a more dynamic custom hook to handle API requests.

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);
        if (!response.ok) throw new Error('Network response was not ok');
        const json = await response.json();
        setData(json);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]); // Runs whenever the URL changes

  return { data, loading, error };
}

export default useFetch;

Enter fullscreen mode Exit fullscreen mode

Usage:

function UserList() {
  const { data, loading, error } = useFetch('<https://jsonplaceholder.typicode.com/users>');

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <ul>
      {data.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

Enter fullscreen mode Exit fullscreen mode

Real-World Applications of Custom Hooks

  1. Authentication : useAuth to manage user login/logout state.
  2. Theme Management : useTheme for switching between light and dark modes.
  3. Form Handling : useForm for input validation and state management.
  4. Debouncing : useDebounce to handle delayed API calls (e.g., search queries).
  5. Animations : useAnimation to abstract animation logic.

Testing Custom Hooks Custom hooks can be tested using libraries like React Testing Library or Jest . A typical test might involve:

  • Mocking useEffect or external dependencies.
  • Testing the output based on different inputs.

Custom hooks enable cleaner, reusable, and scalable codebases . They embody the true power of React, making your application logic modular and easier to maintain.

Top comments (0)