Useful Cheatsheetsusefulcheatsheets.com
React Hooks
Chapter 13 · Page 91
Intermediate

React Hooks

Quick reference for core and advanced React hooks with usage rules and patterns.

TL;DR

  1. 01useState and useEffect cover most common state and side-effect needs.
  2. 02Use useCallback and useMemo only when you have a proven performance issue.
  3. 03Only call hooks at the top level and inside React function components.

Tips

  1. 01Create custom hooks to share logic between components — extract state and effects into reusable hooks with names starting with "use".

Warnings

  1. 01Always follow the Rules of Hooks — calling hooks conditionally or from non-component functions breaks React's internal state management.
Notes
Useful Cheatsheetsusefulcheatsheets.com
React Hooks
Chapter 13 · Page 92
Intermediate

React Hooks

(continued)

Core Hooks

  • useState for managing local component state.
    const [count, setCount] = useState(0);
    return <button onClick={() => setCount(count + 1)}>{count}</button>;
  • useEffect for side effects and cleanup.
    useEffect(() => {
      fetch("/api/data").then(r => r.json()).then(setData);
      return () => { /* cleanup */ };
    }, []);
  • useContext for accessing shared data from a provider.
    const { theme } = useContext(ThemeContext);
    return <div style={{ background: theme }}>Content</div>;
  • useReducer for state with multiple related actions.
    const [state, dispatch] = useReducer(reducer, { count: 0 });
    return <button onClick={() => dispatch({ type: "INCREMENT" })}>
      {state.count}
    </button>;
  • useRef for accessing DOM nodes or storing mutable values.
    const inputRef = useRef(null);
    return (
      <>
        <input ref={inputRef} />
        <button onClick={() => inputRef.current.focus()}>Focus</button>
      </>
    );
Notes
Useful Cheatsheetsusefulcheatsheets.com
React Hooks
Chapter 13 · Page 93
Intermediate

React Hooks

(continued)

Performance Hooks

  • useCallback memoizes a function reference across renders.
    const handleClick = useCallback(() => {
      doSomething(value);
    }, [value]);
  • useMemo memoizes a computed value across renders.
    const expensiveValue = useMemo(() => {
      return computeExpensiveValue(a, b);
    }, [a, b]);
  • Use useCallback to prevent child re-renders when passing callbacks.
    const handleSubmit = useCallback((data) => {
      saveData(data);
    }, []); // stable reference — MemoizedChild won't re-render
    
    return <MemoizedChild onSubmit={handleSubmit} />;
  • Use useMemo to avoid recalculating expensive derived data.
    const sortedItems = useMemo(
      () => [...items].sort((a, b) => a.name.localeCompare(b.name)),
      [items]
    );
  • Both hooks only optimize — they don't change behavior.
    // Add these only after profiling shows a real bottleneck
    // Premature optimization adds complexity without benefit
Notes
Useful Cheatsheetsusefulcheatsheets.com
React Hooks
Chapter 13 · Page 94
Intermediate

React Hooks

(continued)

Ref Hooks

  • useRef creates a mutable ref that persists across renders.
    const inputRef = useRef(null);
    return (
      <>
        <input ref={inputRef} />
        <button onClick={() => inputRef.current.focus()}>Focus</button>
      </>
    );
  • useImperativeHandle exposes custom methods to parent components.
    useImperativeHandle(ref, () => ({
      focus: () => inputRef.current.focus(),
      clear: () => { inputRef.current.value = ""; }
    }));
  • Store mutable values that don't need to trigger re-renders.
    const timerRef = useRef(null);
    function start() { timerRef.current = setInterval(tick, 1000); }
    function stop() { clearInterval(timerRef.current); }
  • Track previous prop or state value for comparisons.
    const prevCountRef = useRef(count);
    useEffect(() => { prevCountRef.current = count; }, [count]);
    const prevCount = prevCountRef.current; // value from last render
  • Forward refs to child components with forwardRef.
    const Input = forwardRef((props, ref) => (
      <input ref={ref} {...props} />
    ));
Notes
Useful Cheatsheetsusefulcheatsheets.com
React Hooks
Chapter 13 · Page 95
Intermediate

React Hooks

(continued)

Advanced Hooks

  • useLayoutEffect runs synchronously before paint — use for measurements.
    useLayoutEffect(() => {
      // Runs before browser paints — safe to read DOM measurements here
      const height = elementRef.current.offsetHeight;
      setHeight(height);
    }, []);
  • useDebugValue shows hook values in React DevTools.
    function useCustomHook(value) {
      useDebugValue(value > 10 ? "large" : "small");
      return value;
    }
  • useTransition marks an update as non-urgent to keep UI responsive.
    const [isPending, startTransition] = useTransition();
    startTransition(() => {
      setSearchResults(results); // won't block input from being typed
    });
  • useDeferredValue defers a value update without a transition.
    const deferredQuery = useDeferredValue(searchQuery);
    const results = useMemo(() => filterList(deferredQuery), [deferredQuery]);
  • useId generates a stable unique ID for accessibility attributes.
    function Input({ label }) {
      const id = useId();
      return (
        <>
          <label htmlFor={id}>{label}</label>
          <input id={id} />
        </>
      );
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
React Hooks
Chapter 13 · Page 96
Intermediate

React Hooks

(continued)

Hook Rules

  • Only call hooks at the top level, never in loops or conditions.
    // Good
    function Component() {
      const [count, setCount] = useState(0);
      useEffect(() => { /* ... */ }, []);
    }
    
    // Bad: hook inside condition
    if (condition) {
      const [count, setCount] = useState(0); // Wrong!
    }
  • Only call hooks from React components or custom hooks.
  • Use ESLint plugin to enforce rules automatically.
    {
      "plugins": ["react-hooks"],
      "rules": {
        "react-hooks/rules-of-hooks": "error",
        "react-hooks/exhaustive-deps": "warn"
      }
    }
  • Custom hooks must start with "use" so React enforces the rules.
    // Good: React treats useWindowWidth as a hook
    function useWindowWidth() {
      const [width, setWidth] = useState(window.innerWidth);
      useEffect(() => {
        const handler = () => setWidth(window.innerWidth);
        window.addEventListener("resize", handler);
        return () => window.removeEventListener("resize", handler);
      }, []);
      return width;
    }
  • Hooks must be called in the same order every render.
    // React tracks hooks by call order — conditional calls break this
    // Move conditions inside the hook body, not around it
    useEffect(() => {
      if (!isLoggedIn) return; // condition inside — safe
    }, [isLoggedIn]);
Notes
Useful Cheatsheetsusefulcheatsheets.com
React Hooks
Chapter 13 · Page 97
Intermediate

React Hooks

(FAQ)

FAQ

Pass a dependency array as the second argument to useEffect — an empty array [] runs the effect once on mount, while listing specific values like [userId] re-runs only when those values change. Avoid placing the fetch URL or options object directly in the dependency array if they're recreated each render, as object identity changes will trigger the effect repeatedly.

useState triggers a re-render when updated, while useRef stores a mutable value in .current that persists across renders without causing re-renders. Use useRef for values you need to track (like timers, previous values, or DOM nodes) but don't want to drive the UI.

Use them only after profiling confirms a real performance problem — wrapping every function or computed value adds overhead and complexity that often outweighs any benefit. The most justified cases are passing stable callbacks to heavily optimized child components (React.memo) or skipping expensive recalculations in tight render loops.

React 18 Strict Mode intentionally double-invokes effects in development to surface bugs in effects that don't properly clean up. Return a cleanup function from your effect to handle unmounting correctly, and your production build will only run the effect once.

Extract the state and effects into a custom hook — a plain JavaScript function whose name starts with 'use' that calls other hooks internally. Each component that calls the custom hook gets its own isolated state, so sharing logic doesn't mean sharing state.