React Hooks are functions that let you "hook into" React state and lifecycle features from function components. They were introduced in React 16.8. Below is a list of common React hooks, their explanations, and examples of usage. Additionally, this guide covers how to create custom hooks.

1. useState

The useState hook lets you add state to function components.

Explanation

useState returns an array with two elements: the current state value and a function to update it.

Usage

import React, { useState } from 'react';

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

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

2. useEffect

The useEffect hook lets you perform side effects in function components.

useEffect With Dependencies

  • useEffect runs after the first render and after every update. You can also specify dependencies to control when the effect runs.

Usage

import React, { useState, useEffect } from 'react';

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

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useEffect With an Empty Dependency Array []

  • Runs only once after the initial render (similar to componentDidMount).
useEffect(() => {
  console.log('This runs only once after the first render');
}, []);
  • Use case: Fetching data when the component mounts, setting up event listeners, etc.

useEffect Without Dependencies

  • Runs on every render (initial and subsequent re-renders).
useEffect(() => {
  console.log('This runs after every render');
});
  • Use case: Running code that doesn’t depend on specific state changes, like logging or animations.

Cleanup Function in useEffect

  • If useEffect returns a function, it acts as a cleanup that runs before the next effect or when the component unmounts.
useEffect(() => {
  const interval = setInterval(() => {
    console.log('Interval running...');
  }, 1000);

  return () => {
    clearInterval(interval); // Cleanup on unmount
  };
}, []);
  • Use case: Cleaning up event listeners, canceling API calls, clearing intervals, etc.

3. useContext

The useContext hook lets you access the value of a context.

Explanation

useContext accepts a context object (the value returned from React.createContext) and returns the current context value.

Usage

import React, { useContext } from 'react';

const MyContext = React.createContext();

function MyComponent() {
  const value = useContext(MyContext);

  return <div>{value}</div>;
}

function App() {
  return (
    <MyContext.Provider value="Hello, World!">
      <MyComponent />
    </MyContext.Provider>
  );
}

4. useReducer

The useReducer hook is an alternative to useState for managing complex state logic.

Explanation

useReducer returns an array with the current state and a dispatch function to trigger state updates.

Usage

import React, { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>
        Increment
      </button>
      <button onClick={() => dispatch({ type: 'decrement' })}>
        Decrement
      </button>
    </div>
  );
}

5. useCallback

The useCallback hook returns a memoized callback.

Explanation

useCallback returns a memoized version of the callback that only changes if one of the dependencies has changed.

Usage

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

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

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

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={increment}>
        Click me
      </button>
    </div>
  );
}

6. useMemo

The useMemo hook returns a memoized value.

Explanation

useMemo only recomputes the memoized value when one of the dependencies has changed.

Usage

import React, { useState, useMemo } from 'react';

function ExpensiveCalculationComponent() {
  const [count, setCount] = useState(0);
  const [value, setValue] = useState('');

  const expensiveCalculation = useMemo(() => {
    // Assume this is an expensive calculation
    return count * 2;
  }, [count]);

  return (
    <div>
      <p>Expensive Calculation: {expensiveCalculation}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <input value={value} onChange={(e) => setValue(e.target.value)} />
    </div>
  );
}

7. useRef

The useRef hook returns a mutable ref object.

Explanation

useRef is useful for accessing DOM elements or persisting values across renders.

Usage

import React, { useRef } from 'react';

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    inputEl.current.focus();
  };

  return (
    <div>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </div>
  );
}

8. useImperativeHandle

The useImperativeHandle hook customizes the instance value that is exposed when using ref.

Explanation

useImperativeHandle should be used with React.forwardRef.

Usage

import React, { useRef, useImperativeHandle, forwardRef } from 'react';

const FancyInput = forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));

  return <input ref={inputRef} />;
});

function Parent() {
  const inputRef = useRef();

  return (
    <div>
      <FancyInput ref={inputRef} />
      <button onClick={() => inputRef.current.focus()}>Focus Input</button>
    </div>
  );
}

9. useLayoutEffect

The useLayoutEffect hook runs after all DOM mutations.

Explanation

useLayoutEffect is similar to useEffect, but it fires synchronously after all DOM mutations.

Usage

import React, { useLayoutEffect, useRef } from 'react';

function LayoutEffectComponent() {
  const divRef = useRef();

  useLayoutEffect(() => {
    console.log(divRef.current.getBoundingClientRect());
  });

  return <div ref={divRef}>Hello, world!</div>;
}

10. useDebugValue

The useDebugValue hook is used to display a label for custom hooks in React DevTools.

Explanation

useDebugValue can be helpful for debugging custom hooks.

Usage

import React, { useState, useDebugValue } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  useDebugValue(isOnline ? 'Online' : 'Offline');

  // Imagine this is an actual implementation
  return isOnline;
}

11. Custom Hooks

Custom hooks let you extract component logic into reusable functions.

Explanation

Custom hooks are normal JavaScript functions that can call other hooks.

Example: useFetch

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch(url)
      .then((response) => response.json())
      .then((data) => {
        setData(data);
        setLoading(false);
      });
  }, [url]);

  return { data, loading };
}

export default useFetch;

Usage of Custom Hook

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

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

  if (loading) {
    return <div>Loading...</div>;
  }

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

export default App;

This guide provides a comprehensive overview of React hooks, their usage, and how to create custom hooks.