Abandon Render Pattern : Track Previous Values Without usePrevious
Update state during render when inputs change; React will abandon and restart the render.
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
- Initialize
prevCountwithcount. - During render, compare
countandprevCount. - If different, set
prevCount(count)to abandon the render. - 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);