Skip to content

Redo vs Redux

  • by

Redo and Redux both promise to make state management predictable, but they approach the problem from opposite ends of the spectrum. One wraps mutations in a transactional log; the other dissolves mutations into pure functions.

Choosing between them is less about popularity and more about the shape of change your application produces hour by hour.

🤖 This article was created with the assistance of AI and is intended for informational purposes only. While efforts are made to ensure accuracy, some details may be simplified or contain minor errors. Always verify key information from reliable sources.

Core Concepts in One Glance

Redo records every mutating operation as a reversible command. Redux replaces the whole state tree with a new copy each time something happens.

Commands in Redo can be replayed, reversed, or grouped into macros. Actions in Redux are plain objects that travel through a single reducer pipeline.

Both systems insist on serializable payloads, yet Redo keeps the original object references alive while Redux treats immutability as law.

State Shape Under Each Model

Redo thrives when state is a nested graph where relationships matter. Redux prefers flat, normalized tables that never alias each other.

A drawing app with live layers keeps each layer as a command target in Redo. The same app in Redux stores layers as an indexed map to avoid deep mutations.

Immutability vs Mutability

Redux copies everything, trusting garbage collection to clean up the debris. Redo mutates in place, trusting its undo stack to resurrect any previous version.

This difference decides whether you can safely pass state to a Web Worker or whether you must clone first.

Developer Experience Compared

Redux DevTools shows a linear timeline of every action, letting you skip backward and forward. Redo DevTools shows a tree of command groups that can be pruned or reordered.

Time-travel debugging feels instantaneous in Redux because snapshots are pre-computed. In Redo you travel by reversing commands, which can feel slower if the command list grows deep.

Learning Curve

Redux demands fluency in reducer composition, middleware, and selectors. Redo demands fluency in command patterns, memento snapshots, and transactional boundaries.

Beginners often misplace async logic in Redux reducers. In Redo they forget to wrap side effects inside commands and end up with unreversible state.

Tooling Ecosystem

Redux offers a buffet of official packages: RTK, RTK Query, Reselect. Redo leans on community plugins for command batching, macro recording, and selective undo.

IDE support favors Redux through type generators and lint rules. Redo plugins are lighter, often just decorating methods with `@command` annotations.

Performance Footprint

Redux allocates a new object graph on every dispatch. Memoization and structural sharing keep this cost low, but the baseline is still a copy.

Redo writes directly to the existing graph, then pushes an inverse operation onto the undo stack. Memory grows linearly with the number of mutations, not the size of state.

Large Dataset Scenarios

A spreadsheet with ten thousand cells triggers ten thousand copies in Redux unless you normalize aggressively. Redo touches only the modified cells and records the delta.

Scrolling a long virtual list feels smoother under Redo because the DOM nodes read from the same mutable objects. Redux lists may stutter if selectors recalculate too often.

Memory Reclamation

Redux can leak when selectors retain outdated computations. Redo can leak when commands hold references to large detached subgraphs.

Both pitfalls disappear once you cap history depth and prune detached nodes.

Testing Strategies

Redux reducers are pure; feed them an action, assert the next state. Redo commands are impure; test them by verifying the undo path returns the original state.

Unit tests for Redux focus on reducer logic. Unit tests for Redo focus on command pairs: forward and reverse.

Integration Testing

Redux tests replay a sequence of actions and assert final UI snapshots. Redo tests replay commands, undo halfway, then redo to ensure the UI returns to the same pixel state.

Cypress suites for Redux mock the store and inject actions. For Redo they trigger real user gestures and inspect the undo stack length.

Property-Based Testing

Redux plays nicely with generative tests because state transitions are deterministic. Redo needs custom generators that produce valid command sequences reversible by construction.

Fuzzing Redux can reveal forgotten action branches. Fuzzing Redo can reveal irreversible commands that corrupt the undo stack.

Scaling to Team Size

Redux centralizes logic in one store, creating a single merge point for conflicting features. Redo distributes logic across commands, letting teams own isolated slices.

A team migrating a legacy canvas app can wrap existing drawing methods as Redo commands without rewriting the model. The same team porting to Redux must first flatten the canvas into normalized entities.

Code Ownership

Redux slices live in folders named after domain nouns. Redo commands live in folders named after user verbs.

Product managers find verb folders intuitive when prioritizing features. They can delete an entire “resize” folder without touching “color” or “move”.

Onboarding New Engineers

Fresh hires read the Redux state shape like a database schema. They read the Redo command catalog like a user manual.

Both documents speed up onboarding, but the Redux doc ages faster as selectors evolve.

Integration with Async Flows

Redux relegates async work to middleware: thunks, sagas, observables. Redo keeps async work inside commands but marks them as non-undoable until completion.

A file upload in Redux dispatches `pending`, `progress`, `success` actions. The same upload in Redo appends an irreversible placeholder command that finalizes once the server confirms.

Error Handling

Redux captures errors in middleware and rolls back optimistically updated state. Redo captures errors inside commands and refuses to push the forward step, leaving state untouched.

Users see an immediate error banner in Redux. In Redo they see the action simply refuse to complete, as if it never happened.

Offline Support

Redux can queue actions while offline and replay them on reconnect. Redo can queue commands but must reconcile them against server truth when the app returns.

Both approaches need a sync strategy, but Redux queues are easier to inspect because they are plain JSON arrays.

Security Considerations

Redux state is readable by any script on the page; sensitive data must live outside the store. Redo state is also readable, but commands can encapsulate encryption before the mutation touches the graph.

A credit card form can keep the card number inside a sealed command payload that never reaches the plain state tree.

Audit Trails

Redo gives you an audit trail for free: every command is already a serialized intent. Redux needs separate audit middleware that duplicates each action to a logging endpoint.

Regulators love Redo’s built-in trail until they realize commands may contain unencrypted PII.

Replay Attacks

Redux actions replayed from DevTools can trigger real API calls if middleware is naive. Redo commands replayed from history can do the same unless commands validate timestamps and nonces.

Both frameworks require explicit whitelisting of safe operations.

Hybrid Architectures

Some apps keep Redux for global UI state and embed Redo inside a single complex widget. The widget exposes its own undo stack while the outer app remains blissfully immutable.

A text editor inside a larger project management tool is a classic candidate for this marriage.

Porting from One to the Other

Porting Redux to Redo starts by identifying bounded contexts that mutate together. Each context becomes a command group with its own history.

Porting Redo to Redux starts by freezing the mutable graph at key frames and treating those frames as Redux states. Commands convert to actions that replace the entire frozen slice.

Coexistence Patterns

Use Redux to drive routing, notifications, and feature flags. Use Redo to drive the canvas, the editor, or any surface where the user expects Ctrl-Z.

Bridge the two with a thin adapter that translates Redux actions into Redo commands when the user crosses into the mutable surface.

Decision Framework

Pick Redux when the app is read-heavy, the state shape is relational, and the team values predictable snapshots. Pick Redo when the app is write-heavy, the user demands fine-grained undo, and the domain logic is already mutation-centric.

If you ship collaborative editing next quarter, Redo’s operational transform layer is easier to graft onto commands. If you ship server-side rendering tomorrow, Redux’s frozen snapshots serialize without extra thought.

Whichever you choose, wrap the boundary clearly, test the edges relentlessly, and never let the implementation leak into user vocabulary.

Leave a Reply

Your email address will not be published. Required fields are marked *