February 18, 2026
react-hooks

React Hooks Cheat Sheet with Practical Code Examples

React Hooks made using state and other features in functional components possible, completely changing the way we create React components. Hooks were first introduced in React 16.8, and they often remove the requirement for class components, making your code simpler to read and manage. In this guide, we’ll explore all React 18 hooks with detailed explanations, practical code examples

What are React Hooks?

React Hooks allows you to use state and lifecycle methods in functional components. They make your code more reusable and reduce the complexity of state management and side effects.

Why Use React Hooks?

  • Simplify state management in functional components.
  • Improve code readability.
  • Promote reusable and testable logic via custom hooks.

Rules of Hooks

Before diving into individual hooks, remember these rules of hooks:

  • Call hooks at the top level: Don’t call hooks inside loops, conditions, or nested functions.
  • Call hooks only in React functions: Use hooks in functional components or custom hooks.

Core Hooks

  • useState
  • useEffect
  • useContext
  • useReducer
  • useCallback
  • useMemo
  • useRef
  • useImperativeHandle

Additional Hooks

  • useLayoutEffect
  • useDebugValue

New React 18 Updates

  • Automatic batching for hooks (useState, useReducer).
  • Improved Suspense for data fetching with hooks.

1. useState: State Management Simplified

React 18 improves automatic batching, which now applies to multiple useState calls within an event handler or function.

import React, { useState } from "react";  

function BatchExample() {  
  const [count, setCount] = useState(0);  
  const [name, setName] = useState("");  

  const handleClick = () => {  
    setCount((prev) => prev + 1);  
    setName("React 18");  
    // Updates are batched together for a single render
  };  

  return (  
    <div>  
      <h1>Count: {count}</h1>  
      <h2>Name: {name}</h2>  
      <button onClick={handleClick}>Update</button>  
    </div>  
  );  
}  

export default BatchExample;  

2. useEffect: Managing Side Effects

React 18 optimizes useEffect with automatic batching for event handlers. Effects continue to fire after the render cycle.

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

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

  useEffect(() => {  
    console.log("Count updated:", count);  
  }, [count]);  

  return (  
    <div>  
      <h1>Count: {count}</h1>  
      <button onClick={() => setCount((prev) => prev + 1)}>Increment</button>  
    </div>  
  );  
}  

export default EffectExample;  

3. React 18 Hooks for Concurrent Rendering

React 18 introduced concurrent rendering, making applications more responsive by breaking rendering into multiple steps. Hooks like useDeferredValue and useTransition allow developers to leverage these features.

4. useTransition: Prioritize UI Updates

The useTransition hook delays less urgent updates, improving responsiveness for high-priority UI tasks.

import React, { useState, useTransition } from "react";  

function TransitionExample() {  
  const [input, setInput] = useState("");  
  const [list, setList] = useState([]);  
  const [isPending, startTransition] = useTransition();  

  const handleChange = (e) => {  
    setInput(e.target.value);  
    startTransition(() => {  
      setList(Array(20000).fill(e.target.value));  
    });  
  };  

  return (  
    <div>  
      <input type="text" value={input} onChange={handleChange} />  
      {isPending && <p>Updating...</p>}  
      <ul>  
        {list.map((item, index) => (  
          <li key={index}>{item}</li>  
        ))}  
      </ul>  
    </div>  
  );  
}  

export default TransitionExample;  

5. useDeferredValue: Avoid Lag in Complex Updates

The useDeferredValue hook defers updates to less urgent UI elements, ensuring smooth interactions.

import React, { useState, useDeferredValue } from "react";  

function DeferredExample() {  
  const [input, setInput] = useState("");  
  const deferredValue = useDeferredValue(input);  

  return (  
    <div>  
      <input type="text" value={input} onChange={(e) => setInput(e.target.value)} />  
      <p>Deferred Value: {deferredValue}</p>  
    </div>  
  );  
}  

export default DeferredExample;  

6. useId: Generate Unique IDs for Accessibility

The useId hook generates unique IDs to improve accessibility and prevent collisions.

import React, { useId } from "react";  

function Form() {  
  const id = useId();  

  return (  
    <form>  
      <label htmlFor={`${id}-username`}>Username</label>  
      <input id={`${id}-username`} type="text" />  

      <label htmlFor={`${id}-password`}>Password</label>  
      <input id={`${id}-password`} type="password" />  
    </form>  
  );  
}  

export default Form;  

7. Improved Suspense with React 18 Hooks

React 18 fully supports data fetching with Suspense, enabling smoother asynchronous UI rendering.

import React, { Suspense } from "react";  

const UserProfile = React.lazy(() => import("./UserProfile"));  

function App() {  
  return (  
    <Suspense fallback={<p>Loading...</p>}>  
      <UserProfile />  
    </Suspense>  
  );  
}  

export default App;  

8. useContext: Access Global State

The useContext hook allows you to consume values from React’s Context API.

import React, { useContext, createContext } from "react";

const ThemeContext = createContext("light");

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <p>Current Theme: {theme}</p>;
}

export default App;

9. useReducer: Advanced State Management

Use useReducer for complex state logic, similar to Redux-like reducers.

import React, { useReducer } from "react";

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, { count: 0 });

  return (
    <div>
      <h1>{state.count}</h1>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </div>
  );
}

export default Counter;

10. useCallback: Optimize Functions

The useCallback hook memoizes a function, preventing it from being re-created unnecessarily.

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

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

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

  return (
    <div>
      <Child onClick={increment} />
      <h1>{count}</h1>
    </div>
  );
}

function Child({ onClick }) {
  console.log("Child rendered");
  return <button onClick={onClick}>Increment</button>;
}

export default Parent;

11. useMemo: Optimize Calculations

The useMemo hook memoizes expensive calculations to improve performance.

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

function ExpensiveCalculation({ num }) {
  const compute = (n) => {
    console.log("Calculating...");
    return n * 2;
  };

  const result = useMemo(() => compute(num), [num]);

  return <h1>Result: {result}</h1>;
}

export default ExpensiveCalculation;

12. useRef: Access DOM Elements

The useRef hook provides a way to reference DOM nodes or persist values across renders.

import React, { useRef } from "react";

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

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}

export default TextInput;

13.useImperativeHandle: Customize Ref Behavior

This hook customizes the ref behaviour for a child component.

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

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

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

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

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

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

export default Parent;

14. Custom Hooks

Custom hooks allow you to encapsulate reusable logic.

import { useState, useEffect } from "react";

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

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

  return data;
}

React hooks simplify the way you manage state, side effects, and reusable logic. By mastering hooks, you can write cleaner and more maintainable React applications. Share your favourite hooks in the comments below!

Leave a Reply

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

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.