⚛️ React Q47 / 113

What is custom hook in React?

AI-Powered Answer ✓ Answered

Custom Hooks are a powerful feature in React that allow you to extract reusable stateful logic from your components and share it across your application. They promote cleaner code, better organization, and easier testing by separating concerns.

What is a Custom Hook?

A custom Hook is a JavaScript function whose name starts with 'use' and that can call other Hooks (like useState, useEffect, useContext, etc.). Its primary purpose is to encapsulate and share stateful logic between components without sharing the state itself. When multiple components use the same custom hook, each component gets its own independent copy of the state managed by that hook.

Custom Hooks solve the problem of code duplication when you need to use the same logic (e.g., fetching data, handling form input, managing timers) in multiple components. Instead of copy-pasting code or relying on complex Higher-Order Components (HOCs) or render props for simple logic, custom hooks provide a more direct and readable way to reuse functionality.

Why Use Custom Hooks?

  • Reusability: Share stateful logic across multiple components without duplicating code.
  • Readability & Maintainability: Encapsulate complex logic in a single place, making components smaller, more focused, and easier to understand.
  • Separation of Concerns: Decouple logic from presentation, making your components purely responsible for rendering UI.
  • Easier Testing: Logic encapsulated within a custom hook can often be tested in isolation, simplifying unit testing.
  • Avoidance of Wrapper Hell: Offers a cleaner alternative to HOCs or render props for sharing stateful logic, preventing nested component trees.

How to Create a Custom Hook

Creating a custom Hook is straightforward. You define a JavaScript function, adhere to the naming convention (starting with use), and utilize built-in React Hooks within it.

Example: A simple `useCounter` hook

jsx
import { useState, useCallback } from 'react';

function useCounter(initialValue = 0) {
  const [count, setCount] = useState(initialValue);

  const increment = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, []);

  const decrement = useCallback(() => {
    setCount(prevCount => prevCount - 1);
  }, []);

  const reset = useCallback(() => {
    setCount(initialValue);
  }, [initialValue]);

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

And here's how you would use this useCounter hook in a functional component:

jsx
import React from 'react';
// Assuming useCounter is in a separate file like 'hooks/useCounter.js'
import useCounter from './useCounter'; 

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

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

Notice that CounterComponent only concerns itself with rendering, while useCounter handles all the stateful logic related to counting. If another component also needed a counter, it could simply call useCounter() and get its own independent counter logic and state.

Key Rules and Considerations

  • Naming Convention: Always start your custom Hook function names with use (e.g., useToggle, useFetchData). This is crucial because React relies on this convention to apply the 'Rules of Hooks' and linting checks.
  • Call from Functional Components or Other Hooks: You can only call Hooks from React functional components or from other custom Hooks. You cannot call them from regular JavaScript functions.
  • Do Not Return JSX: Custom Hooks are for logic, not for rendering. They typically return an array or an object containing values and functions that the component can use.
  • Separate State: Each component that calls a custom Hook gets its own isolated state. Custom Hooks are not a mechanism to share state between components directly, but rather to share the *logic* that manages state.