20. Build a usePrevious Hook — Track a Value's Last Render

easy

A short hook that's really a question about render-vs-effect timing. The whole trick is that the effect runs after render.

Why it works

During a render, you return ref.current — which still holds whatever the last committed effect wrote, i.e. the previous value. Then the effect runs and updates the ref for next time. On the first render the ref is undefined, which is the expected "no previous value yet".

The key insight

  • Refs persist across renders without causing re-renders.
  • Mutating a ref during render is a side effect — keep the write in useEffect, exactly so the return value lags by one render.

Follow-ups

  • "Why not useState?" → setting state would trigger an extra render and create a feedback loop.
  • "Get the previous value of several props?" → store an object in the ref, or call the hook per value.

What to practice

Write it, then explain out loud the order: render returns old value → React commits → effect writes new value.

More questions

index.js
import { useEffect, useRef } from "react";

function usePrevious(value) {
  // return the value from the previous render (undefined on the first)
}

// Usage:
// const prevCount = usePrevious(count);
// useEffect(() => { if (prevCount !== undefined && count > prevCount) {...} });

Tests

Test Code

Enter JavaScript that runs after your solution. It should return a value or a Promise.