DEV Community

Gerald Hamilton Wicks
Gerald Hamilton Wicks

Posted on

3 Essential React Hooks You Should Have in Your Project

React hooks are powerful tools for managing state and side effects in your applications. While hooks like useState, useEffect, and useReducer are built into React, it's often beneficial to create custom hooks tailored to your specific needs. Here are three essential custom hooks that you should consider adding to your project:

1. useFetch

Handling requests to a backend server is a common task in almost every project. Instead of using the native JavaScript fetch function repeatedly, you can create a custom hook to manage this logic:

import { useEffect, useState } from "react";

/**
 * Custom hook to fetch data from a given URL.
 *
 * @template T - The type of the data being fetched.
 * @param {string} url - The URL to fetch data from.
 * @param {RequestInit | undefined} options - The options to pass to the fetch request.
 * @returns {[T | null, boolean, unknown | null]} - An array containing the fetched data, loading state, and error state.
 */
export function useFetch<T>(url: string, options?: RequestInit): [T | null, boolean, unknown | null] {
  // State to store the fetched data
  const [data, setData] = useState<T | null>(null);

  // State to store the loading status
  const [isLoading, setIsLoading] = useState<boolean>(false);

  // State to store any error that occurs during the fetch
  const [error, setError] = useState<unknown | null>(null);

  // useEffect hook to trigger the fetch operation whenever the URL or options change
  useEffect(() => {
    fetchData();
  }, [url, options]);

  /**
   * Function to fetch data from the provided URL.
   *
   * This function handles the fetch operation, updates the loading state,
   * sets the fetched data, and handles any errors that occur during the fetch.
   */
  async function fetchData(): Promise<void> {
    // Set loading state to true before starting the fetch
    setIsLoading(true);

    try {
    // Perform the fetch operation
    const response = await fetch(url, options);

    // Parse the response data as JSON
    const responseData = await response.json();

    // Update the state with the fetched data
    setData(responseData);

    // Clear any previous error
    setError(null);
    } catch (error) {
    // Update the state with the error if the fetch fails
    setError(error);
    } finally {
    // Set loading state to false after the fetch is complete
    setIsLoading(false);
    }
  }

  // Return the fetched data, loading state, and error state
  return [data, isLoading, error];
}
Enter fullscreen mode Exit fullscreen mode

2. useLocalStorage

Storing data on the client side, such as in localStorage, is a common requirement for caching and saving useful information. This custom hook helps you get and set data in localStorage:

import { useEffect, useState } from "react";

/**
 * A custom hook that synchronizes a state variable with localStorage.
 *
 * @template T The type of the stored value.
 * @param {string} key The key under which the value is stored in localStorage.
 * @returns {[T | null, (value: T) => void]} A stateful value and a function to update it.
 *
 * @example
 * const [name, setName] = useLocalStorage<string>('name');
 * setName('Alice');
 * console.log(name); // 'Alice'
 */
export function useLocalStorage<T>(
  key: string,
): [T | null, (value: T) => void] {
  // Initialize state with null
  const [data, setData] = useState<T | null>(() => null);

  // useEffect to retrieve and set the data from localStorage on mount and when the key changes
  useEffect(() => {
    setData(() => {
    // Get the data from localStorage
    const localStorageData = localStorage.getItem(key);

    // If data exists, parse and return it; otherwise, return null
    if (localStorageData) {
        return JSON.parse(localStorageData);
    } else {
        return null;
    }
    });
  }, [key]); // Dependency array with key ensures this runs when key changes

  /**
   * Updates the localStorage value and the state.
   *
   * @param {T} value The value to store.
   */
  function setLocalStorage(value: T): void {
    // Store the value in localStorage
    localStorage.setItem(key, JSON.stringify(value));

    // Update the state to trigger rerender
    setData(() => value);
  }

  // Return the stateful value and the updater function
  return [data, setLocalStorage];
}
Enter fullscreen mode Exit fullscreen mode

3. useToggle

One of the simplest yet most useful hooks is useToggle. This hook manages a boolean state, making it easy to toggle between true and false. This is particularly useful for UI elements like dropdowns:

import { useState, Dispatch, SetStateAction } from "react";

/**
 * A custom hook that provides a boolean state with a toggle function.
 *
 * @param {boolean} [initialValue=false] The initial value of the toggle state.
 * @returns {[boolean, () => void, Dispatch<SetStateAction<boolean>>]} An array containing:
 *   - The current boolean state.
 *   - A function to toggle the state.
 *   - The state setter function.
 *
 * @example
 * const [isOpen, toggleIsOpen, setIsOpen] = useToggle(false);
 * toggleIsOpen(); // Toggles the state
 * console.log(isOpen); // true or false
 */
export function useToggle(
  initialValue?: boolean
): [boolean, () => void, Dispatch<SetStateAction<boolean>>] {
  // Initialize the state with the initial value or default to false
  const [isToggle, setIsToggle] = useState<boolean>(() => initialValue ?? false);

  /**
   * Function to toggle the boolean state.
   */
  function toggle(): void {
    // Toggle the state value
    setIsToggle(value => !value);
  }

  // Return the current state, the toggle function, and the state setter
  return [isToggle, toggle, setIsToggle];
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Understanding and utilizing React hooks is key to creating powerful and efficient applications. While it's common to write logic directly inside React components, repetitive patterns suggest it's time to create custom hooks. With useFetch, useLocalStorage, and useToggle, you can enhance your toolkit and streamline your development process.

What custom hook do you use the most? Let me know in the comments below! :D

Top comments (2)

Collapse
 
abdullah-dev0 profile image
Abdullah

nice Work Keep it up !

Collapse
 
geraldhamiltonwicks profile image
Gerald Hamilton Wicks

Thanks for the feedback