Developers have long dreaded undo/redo. It’s that feature everyone wants — fluid back-and-forth in apps like todo lists or editors — but implementing it? Pure drudgery. Expectations were low: you’d hack states per project, bloating reducers with iffy history arrays. Then Redux dropped this enhancer. Boom. Generic undo manager for React apps, no Redux mandate needed.
This changes everything. Suddenly, your state machine handles time travel out of the box. No more ‘just for todos’ logic creeping everywhere.
Here’s the thing. Redux’s docs nailed it years ago, and it’s still gold in 2024. State isn’t flat anymore:
past: Array<T>,
present: T,
future: Array<T>
Past holds snapshots before now. Present? Obvious. Future stacks what you’ve undone. Undo shifts present left, pushes to future. Redo reverses it. Simple array ops. No diffs, no compression headaches.
Take their todo example. Empty list. Add ‘Buy milk’ — past gets [], present [“Buy milk”]. Add ‘Walk dog’ — past [[], [“Buy milk”]], present [“Buy milk”, “Walk dog”]. Undo? Present shrinks, full list jumps to future. Dead simple.
“The really nice part is that this logic doesn’t have to live inside your reducer. You can extract it into a reusable wrapper, or as Redux calls it, a reducer enhancer.”
Spot on. That’s the quote that hooked me. Redux enhancer pattern — wrap any reducer, inject undo/redo. Your todos reducer stays pristine:
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, action.text];
default:
return state;
}
}
Slap on undoable(todos). Dispatch ADD_TODO twice, UNDO. Access state.present. Check past.length for undo-ability. It’s composable fire.
Why Does Redux’s Undo Pattern Dominate React Apps in 2024?
Market data doesn’t lie. Redux holds 40%+ of React state management share (State of JS 2023). Zustand, Jotai nibble edges with hooks simplicity — but for undo? Redux wins. Why? Scale. Enterprise apps (think Figma clones, Notion rivals) crave this battle-tested history stack. No mutations sneaking in.
Custom solutions? They fragment. I’ve seen teams burn weeks diffing objects with libraries like use-undo — fine for hooks, but brittle at depth. Redux’s snapshots? Immutable by design if your reducer is. Predictable. And here’s my unique insight: it’s the devtools precursor. Redux DevTools time-travel? Same DNA. Back in 2015, this pattern foreshadowed browser inspectors everywhere. Today, with React Compiler incoming, it’ll revive — pure reducers shine when compiler optimizes away boilerplate.
But wait. Does it bloat memory? Snapshots stack up. Yeah, for massive states (say, 10k-node diagrams), you’re shoving full copies. Future-proof? Add throttling — limit past to 50 steps. Or hybrid with diffs via immer. Still, for 90% of apps? Perfect.
The code’s elegant too. That undoable function — 30 lines. Handles UNDO, REDO, defaults to normal reduce but snapshots on change. Clears future on new actions. Genius.
And composability? Stack enhancers. Undoable logging. Undoable persistence. Layers without tears.
redux-undo library packages it. 10k stars. Plug-and-play.
Can You Build a Generic Undo Manager for React Without Redux?
Absolutely. Port to hooks. useReducer with this state shape. Custom dispatcher wrapping actions. But Redux’s enhancer edge? Higher-order purity. Hooks tangle local state.
Look, React Query, TanStack — they’re query-focused. Undo needs action history. This pattern fills the gap. Skeptical? Test it. Fork a CRA, add this. Undo feels native.
Critique time. Original post hypes ‘elegant’ — fair, but glosses perf. For React Native? Snapshots murder battery on mobile lists. Mitigation: shallow copy primitives only.
Part 2 teases another way. Betting command pattern — stack actions, replay. Better for optimistic updates. Stay tuned.
Data point: GitHub searches for ‘react undo’ spike 20% YoY. Demand’s there. This scratches it generically.
Bold call — React 19 ships, hooks fatigue hits. Redux patterns resurge via adapters like Redoodle. Watch.
🧬 Related Insights
- Read more: One 💩 Emoji Froze a 10k-Row Data Pipeline at Row 6,842
- Read more: RBAC + ABAC: The Hybrid Shield Every Node.js API Needs in 2026
Frequently Asked Questions
What is a generic undo manager for React?
It’s a wrapper turning any state reducer into undo/redo-ready history keeper, using past/present/future snapshots — no app-specific hacks.
Does Redux undo work with functional React components?
Yes, via hooks or context; access present state, dispatch UNDO/REDO actions smoothly.
Is redux-undo better than building from scratch?
For most? Yes — battle-tested, tiny bundle, zero config beyond wrapping your reducer.