• Home
  • My Story
  • Projects
  • Blog
  • Reach Out

Building Custom Hooks in JavaScript with React

February 26, 2024 (1y ago)

React's hooks API has revolutionized how we manage state and side effects in functional components. While built-in hooks like useState and useEffect are incredibly useful, custom hooks take this a step further by allowing you to encapsulate reusable logic and share it across multiple components.

What Are Custom Hooks?

Custom hooks are JavaScript functions that can use built-in React hooks to manage state and side effects. They provide a way to extract component logic into reusable functions, making your components cleaner and easier to maintain.

Why Use Custom Hooks?

  • Reusability: Encapsulate logic that can be reused across multiple components.
  • Abstraction: Keep your components cleaner by moving complex logic into hooks.
  • Separation of Concerns: Separate state management and side effects from your component's rendering logic.

Creating a Custom Hook

Let's start with a basic example of a custom hook for managing a counter.

1. Creating the Hook

Create a file named useCounter.js (or .ts if you’re using TypeScript) and define your custom hook:

import { useState } from 'react';

// Custom hook to manage counter state
function useCounter(initialValue = 0) {
  const [count, setCount] = useState(initialValue);

  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);
  const reset = () => setCount(initialValue);

  return { count, increment, decrement, reset };
}

export default useCounter;

2. Using the Hook in a Component

Now that we have our custom hook, let’s use it in a component:

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

function CounterComponent() {
  const { count, increment, decrement, reset } = useCounter(10);

  return (
    <div>
      <h1>Counter: {count}</h1>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

export default CounterComponent;

Custom Hook for Managing API Calls

Custom hooks can also be used to handle side effects like data fetching. Here’s an example:

1. Creating the Hook

Create a file named useFetch.js:

import { useState, useEffect } from 'react';

// Custom hook to fetch data from an API
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 result = await response.json();
        setData(result);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;

2. Using the Hook in a Component

Here’s how you might use useFetch in a component:

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

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

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

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

export default DataFetchingComponent;

Tips for Custom Hooks

  1. Name Conventions: Always start custom hooks with use (e.g., useCounter, useFetch) to follow React’s convention and make hooks recognizable.
  2. Avoid Calling Hooks Conditionally: Custom hooks should always be called at the top level of your component or another hook to ensure the rules of hooks are followed.
  3. Encapsulate Complex Logic: Use custom hooks to simplify your components by moving complex logic into hooks.

By building custom hooks, you can enhance the modularity and reusability of your React components. They help keep your code DRY (Don't Repeat Yourself) and improve the maintainability of your codebase. Happy coding!