Custom Hooks in React

Loading

Custom hooks in React are JavaScript functions that allow you to reuse stateful logic across multiple components. They enable you to abstract common functionality into reusable pieces, making your code more modular, readable, and maintainable.

1. What Are Custom Hooks?

Custom hooks are functions that can call other hooks (like useState, useEffect, etc.) and return values or functions that can be used by components. They allow you to extract and reuse stateful logic, making your components cleaner and reducing code duplication.

Custom hooks are prefixed with “use” to follow React’s convention, which allows React to differentiate hooks from normal JavaScript functions.

Example of a Custom Hook:

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      return initialValue;
    }
  });

  const setValue = (value) => {
    try {
      setStoredValue(value);
      window.localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.error("Could not store value", error);
    }
  };

  return [storedValue, setValue];
}

In this example:

  • useLocalStorage is a custom hook that abstracts away the logic for working with localStorage.
  • It returns the stored value from localStorage and a function to update the value in localStorage.

2. Why Use Custom Hooks?

Custom hooks allow you to:

  • Reusability: Extract and reuse stateful logic across multiple components.
  • Readability: Organize complex logic into separate functions, making your component code cleaner and easier to read.
  • Encapsulation: Hide implementation details of logic while exposing only necessary values or methods to the components using the hook.
  • Avoid Duplication: Prevent code duplication by encapsulating common behavior that can be used in multiple places.

3. Example: Using a Custom Hook

Now let’s see how the useLocalStorage hook can be used in a component.

import React, { useState } from 'react';
import { useLocalStorage } from './useLocalStorage'; // Assuming custom hook is in this file

function App() {
  const [name, setName] = useLocalStorage('name', 'John Doe'); // Using the custom hook
  const [age, setAge] = useState(25);

  return (
    <div>
      <h1>Custom Hook Example</h1>
      <p>Name: {name}</p>
      <p>Age: {age}</p>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)} // Updates name in localStorage
      />
      <button onClick={() => setAge(age + 1)}>Increase Age</button>
    </div>
  );
}

export default App;

In this example:

  • useLocalStorage manages the name state with localStorage. Any changes to name will automatically be saved to localStorage and retrieved when the component is rendered.

4. How to Create a Custom Hook

Creating a custom hook follows a simple pattern:

  1. Define the hook: Create a JavaScript function that starts with use (e.g., useFetch, useLocalStorage).
  2. Use built-in hooks: Inside the custom hook, use React’s built-in hooks like useState, useEffect, useRef, etc.
  3. Return values or functions: Return whatever data or functionality your hook needs to provide to the component.

Example: Custom Hook for Fetching Data

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 result = await response.json();
        setData(result);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

This custom hook useFetch is designed to fetch data from a URL, manage the loading state, and handle any errors that may occur.

You can use it in a component as follows:

import React from 'react';
import { useFetch } from './useFetch'; // Assuming custom hook is in this file

function App() {
  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>Fetched Data</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

export default App;

5. Best Practices for Custom Hooks

  • Start with use: Always start the custom hook name with use (e.g., useLocalStorage, useFetch) to follow React’s naming convention for hooks.
  • Keep hooks small: A custom hook should do one thing well. If your hook does too many things, consider breaking it into smaller hooks.
  • Use multiple hooks: Custom hooks can use other hooks (like useState, useEffect, etc.) inside them, making them a flexible way to combine logic.
  • Return only necessary data: Return only what is needed by the component that uses the hook. This could be state, functions, or data.
  • Avoid side effects outside useEffect: If your custom hook requires side effects (e.g., API calls, localStorage), make sure to use useEffect to handle those.

Leave a Reply

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