Back to all notes

Abandon Render Pattern : Track Previous Values Without usePrevious

Update state during render when inputs change; React will abandon and restart the render.

2 min read

Introduction

The abandon render pattern lets you update state during render when an input changes. React abandons the current render and restarts with the new state, which is useful for tracking previous values without extra hooks.

Why this matters

React supports updating state during render in specific cases. If you detect that an input changed, you can set state immediately to keep a derived “previous” value—React abandons the current render and retries with the new state.

The problem

Tracking previous values with custom hooks or effects often adds extra state and renders.

Inefficient approach

Using an effect or a custom usePrevious hook:

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

function usePrevious(value) {
  const ref = useRef(value);
  useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
}

function App() {
  const [count, setCount] = useState(0);
  const prevCount = usePrevious(count);

  return (
    <div>
      <h1>Abandon Render Pattern</h1>
      <p>Current: {count}</p>
      <p>Previous: {prevCount}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

export default App;

The solution

Track prevCount with state and update it when count changes.

import { useState } from "react";

function App() {
  const [count, setCount] = useState(0);
  const [prevCount, setPrevCount] = useState(count);

  if (count !== prevCount) {
    setPrevCount(count); // abandon render, restart with new prevCount
  }

  return (
    <div>
      <h1>Abandon Render Pattern</h1>
      <p>Current: {count}</p>
      <p>Previous: {prevCount}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

export default App;

Step-by-step

  1. Initialize prevCount with count.
  2. During render, compare count and prevCount.
  3. If different, set prevCount(count) to abandon the render.
  4. Render both values as needed; avoid side effects here.

Tips

  • Keep abandon‑render updates minimal and deterministic.
  • Don’t trigger side effects here—those belong in effects.
  • If you only need logging, prefer an effect keyed by the dependency.

Knowledge base

Problem snippet:

const prev = usePrevious(count);

Solution snippet:

const [prevCount, setPrevCount] = useState(count);
if (count !== prevCount) setPrevCount(count);