React Hooks Cheatsheet – All Hooks Explained with Syntax

React Hooks Cheatsheet – All Hooks Explained with Syntax

Master React Hooks with this complete, up-to-date cheatsheet for React 19.2. Includes every React Hook — from useState and useEffect to useFormStatus and useOptimistic — with clear explanations, syntax, and examples.

Perfect quick reference for React developers, from beginner to pro.

React Hooks Cheatsheet(Updated for React 19.2)

State Hooks: useState

The most fundamental React Hook for managing state inside functional components. It returns an array with a state variable and a setter function. The initial value is set only on the first render, and React preserves the value between renders. Ideal for managing UI states like toggles, form inputs, counters, or visibility flags.

import { useState } from 'react';

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

  const increment = () => setCount(prev => prev + 1);
  const reset = () => setCount(0);

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

State Hooks: useReducer

An alternative to useState for managing more complex or related pieces of state. It follows a reducer pattern (similar to Redux) where you define a reducer function that handles different action types. Great for complex UIs, multi-step forms, or scenarios with intricate state transitions.

import { 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:
      return state;
  }
}

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

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

Effect Hooks: useEffect

Runs side effects after every render by default (or when dependencies change). Side effects include data fetching, DOM updates, subscriptions, or event listeners. The cleanup function runs before the effect re-runs or when the component unmounts, ensuring proper resource management.

import { useEffect, useState } from 'react';

function FetchUser() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    async function getUser() {
      const res = await fetch('https://jsonplaceholder.typicode.com/users/1');
      const data = await res.json();
      setUser(data);
    }
    getUser();
  }, []);

  return user ? <p>{user.name}</p> : <p>Loading...</p>;
}

Effect Hooks: useLayoutEffect

Works just like useEffect but fires synchronously after all DOM mutations and before the browser paints. It’s useful when you need to measure DOM elements, perform layout calculations, or make visual adjustments that must happen before the browser paints the screen.

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

function Box() {
  const boxRef = useRef();
  const [boxWidth, setBoxWidth] = useState(0);

  useLayoutEffect(() => {
    const width = boxRef.current.getBoundingClientRect().width;
    setBoxWidth(width);
  }, []);

  return <div ref={boxRef}>Box width: {boxWidth}px</div>;
}

Effect Hooks: useInsertionEffect

Runs before any DOM mutations. It's primarily used by CSS-in-JS or styling libraries to insert styles before the browser paints. It ensures visual consistency and avoids flickering during hydration or style injection.

import { useInsertionEffect } from 'react';

function ThemedComponent() {
  useInsertionEffect(() => {
    const style = document.createElement('style');
    style.textContent = `.highlight { color: red; }`;
    document.head.appendChild(style);
    return () => document.head.removeChild(style);
  }, []);
  return <p className="highlight">Styled before paint!</p>;
}

Context Hooks: useContext

Lets components access values from a React Context directly, without prop drilling. Perfect for global data like theme, authentication, or language. When the context value changes, all consuming components re-render.

import { createContext, useContext } from 'react';

const ThemeContext = createContext('light');

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

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

Ref Hooks: useRef

Creates a mutable object with a .current property that persists across renders. It’s often used to directly access DOM elements or store any mutable value that doesn’t trigger a re-render when changed.

import { useRef } from 'react';

function InputFocus() {
  const inputRef = useRef(null);

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

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

Ref Hooks: useImperativeHandle

Customizes what gets exposed when using a ref with forwardRef. You can define controlled APIs for a child component so the parent can call specific functions safely.

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

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

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

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

function App() {
  const inputRef = useRef();
  return <><Input ref={inputRef} /><button onClick={() => inputRef.current.focus()}>Focus Input</button></>;
}

Memoization Hooks: useMemo

Caches the result of an expensive computation and only recomputes when dependencies change. Prevents unnecessary recalculations in performance-sensitive applications like filtering or sorting large datasets.

import { useMemo, useState } from 'react';

function FilteredList({ items }) {
  const [query, setQuery] = useState('');

  const filteredItems = useMemo(() => {
    return items.filter(item => item.toLowerCase().includes(query.toLowerCase()));
  }, [query, items]);

  return (
    <div>
      <input value={query} onChange={e => setQuery(e.target.value)} />
      <ul>{filteredItems.map(i => <li key={i}>{i}</li>)}</ul>
    </div>
  );
}

Memoization Hooks: useCallback

Returns a memoized version of a callback function that only changes if dependencies change. It’s especially useful when passing callbacks to memoized or pure child components to avoid unnecessary re-renders.

import { useCallback, useState } from 'react';

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

  const handleClick = useCallback(() => {
    setCount(prev => prev + 1);
  }, []);

  return <Child onClick={handleClick} count={count} />;
}

function Child({ onClick, count }) {
  return <button onClick={onClick}>Clicked {count} times</button>;
}

Performance Hooks (React 18+): useTransition

Marks updates as non-urgent, allowing React to prioritize important updates. Ideal for complex UIs like search or tab changes, where immediate feedback is more important than rendering the final result instantly.

import { useTransition, useState } from 'react';

function SearchList({ items }) {
  const [query, setQuery] = useState('');
  const [isPending, startTransition] = useTransition();

  const handleChange = (e) => {
    const value = e.target.value;
    startTransition(() => setQuery(value));
  };

  const filtered = items.filter(i => i.includes(query));
  return (
    <div>
      <input onChange={handleChange} placeholder="Search..." />
      {isPending && <p>Updating...</p>}
      <ul>{filtered.map(i => <li key={i}>{i}</li>)}</ul>
    </div>
  );
}

Performance Hooks (React 18+): useDeferredValue

Lets you defer re-rendering of non-urgent parts of your UI. Great for heavy components that depend on fast-changing inputs, such as search results or large lists.

import { useDeferredValue } from 'react';

function SearchResults({ query }) {
  const deferredQuery = useDeferredValue(query);
  const results = expensiveSearch(deferredQuery);

  return <ul>{results.map(r => <li key={r}>{r}</li>)}</ul>;
}

Performance Hooks (React 18+): useId

Generates a unique, consistent ID that works on both client and server. Commonly used for accessibility attributes like aria-labelledby or for associating labels with form inputs.

import { useId } from 'react';

function FormInput() {
  const id = useId();
  return (
    <div>
      <label htmlFor={id}>Email</label>
      <input id={id} type="email" />
    </div>
  );
}

React 19 Hooks: useFormStatus

Accesses the status of a form submission (pending, success, or error). Useful for disabling buttons or showing loaders while submitting forms.

function SubmitButton() {
  const { pending } = useFormStatus();
  return <button disabled={pending}>{pending ? 'Submitting...' : 'Submit'}</button>;
}

React 19 Hooks: useActionState

Manages form state and feedback during server actions. Perfect for React 19’s Server Actions — it automatically tracks loading, success, and error states when submitting forms or performing mutations like creating or deleting data.

export default function FeedbackForm() {
  const [state, formAction] = useActionState(async (prevState, formData) => {
    const message = formData.get('message');
    const result = await submitFeedback(message);
    return { status: result.ok ? 'success' : 'error' };
  }, { status: 'idle' });

  return (
    <form action={formAction}>
      <textarea name="message" placeholder="Share your thoughts..." />
      <button type="submit">
        {state.status === 'idle' && 'Submit'}
        {state.status === 'success' && 'Thanks!'}
        {state.status === 'error' && 'Try Again'}
      </button>
    </form>
  );
}

React 19 Hooks: useOptimistic

Helps you provide instant feedback in the UI while waiting for a server update. Ideal for optimistic UI patterns where you update the interface first, then reconcile with the actual server response — like instantly showing a new comment before it's confirmed.

function Comments({ comments }) {
  const [optimisticComments, addOptimisticComment] = useOptimistic(comments);

  async function handleAddComment(text) {
    addOptimisticComment([...optimisticComments, { id: Date.now(), text }]); // Instant UI feedback
    await postCommentToServer(text); // Then sync with backend
  }

  return (
    <div>
      {optimisticComments.map(c => <p key={c.id}>{c.text}</p>)}
      <button onClick={() => handleAddComment('Great post!')}>Add Comment</button>
    </div>
  );
}

React 19 Hooks: use

Allows you to consume promises or async data directly in components. Suspends rendering until the promise resolves — simplifying data fetching in server and async components.

const user = use(fetchUser());
return <p>{user.name}</p>;

Custom Hooks: Writing Custom Hooks

Custom hooks let you encapsulate reusable logic by combining built-in hooks. They make complex behavior (like data fetching, form handling, or persistence) easily shareable between components. Always prefix the function name with 'use' so React can correctly track hook usage.

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    const saved = localStorage.getItem(key);
    return saved ? JSON.parse(saved) : initialValue;
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}

// Usage
function ThemeToggle() {
  const [theme, setTheme] = useLocalStorage('theme', 'light');
  return <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>{theme}</button>;
}

Learn Full Stack

with tapaScript

By clicking Sign Up you re confirming that you agree with our Terms and Conditions.

newsletter

Don't forget to connect with us on