Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungWhy Claude Code keeps writing shell commands that fail on your Mac(20.09.2026 um 21:06 Uhr)
Sichere Programmierungllms.txt v2: What the Spec Says, and What 137,000 Domains Show(20.09.2026 um 21:17 Uhr)
Sicherheitslücken (CVE)NiceTryGPT: Less pattern matching. More actual hacking.(20.09.2026 um 21:19 Uhr)
IT Security VideoActivities BoF (kde2026)(20.09.2026 um 00:00 Uhr)
IT Security Toolsirdoc-app(20.09.2026 um 20:33 Uhr)
Sichere ProgrammierungWhy Claude Code keeps writing shell commands that fail on your Mac(20.09.2026 um 21:06 Uhr)
Sichere Programmierungllms.txt v2: What the Spec Says, and What 137,000 Domains Show(20.09.2026 um 21:17 Uhr)
Sicherheitslücken (CVE)NiceTryGPT: Less pattern matching. More actual hacking.(20.09.2026 um 21:19 Uhr)
IT Security VideoActivities BoF (kde2026)(20.09.2026 um 00:00 Uhr)
IT Security Toolsirdoc-app(20.09.2026 um 20:33 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Generic Undo Manager for React - Part 1

Reagiere als Erste:r — dein Feedback zählt!

It’s probably my third day writing here. I’m not trying to keep a daily streak, but I get genuinely excited when I come across good code, so I end up wanting to share it right away.

Some background

In a personal project I’ve been working on, I spent the past week trying to find a clean, generic way to implement undo/redo without ending up with a bunch of hardcoded states. I wanted something that could manage itself instead of turning into a mess over time.

I’m glad to say I found two solid approaches. You can probably guess that from the title since this is Part 1 😄

In this part, I’ll walk through one approach that I found really elegant—the one recommended by Redux.

The idea

The core idea is simple. Instead of just storing your current state, you store a bit of history along with it.

{
  past: Array<T>,
  present: T,
  future: Array<T>
}
  • past → everything that came before
  • present → your current state
  • future → everything you’ve undone

Undo and redo then become operations where you just move state between these three.

Example: Todo list

Let’s walk through a simple todo list to make this concrete.

Start with an empty list:

past: []
present: []
future: []

Now you add a todo: "Buy milk"

past: [[]]
present: ["Buy milk"]
future: []

Add another todo: "Walk dog"

past: [[], ["Buy milk"]]
present: ["Buy milk", "Walk dog"]
future: []

Add one more: "Read book"

past: [[], ["Buy milk"], ["Buy milk", "Walk dog"]]
present: ["Buy milk", "Walk dog", "Read book"]
future: []

Now hit undo:

past: [[], ["Buy milk"]]
present: ["Buy milk", "Walk dog"]
future: [["Buy milk", "Walk dog", "Read book"]]

Hit undo again:

past: [[]]
present: ["Buy milk"]
future: [["Buy milk", "Walk dog"], ["Buy milk", "Walk dog", "Read book"]]

And if you redo:

past: [[], ["Buy milk"]]
present: ["Buy milk", "Walk dog"]
future: [["Buy milk", "Walk dog", "Read book"]]

This works because you’re not doing anything fancy—you’re just moving snapshots around.

Making it reusable

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.

function undoable(reducer) {
  const initialState = {
    past: [],
    present: reducer(undefined, {}),
    future: []
  }

  return function (state = initialState, action) {
    const { past, present, future } = state

    switch (action.type) {
      case 'UNDO': {
        const previous = past[past.length - 1]
        const newPast = past.slice(0, past.length - 1)

        return {
          past: newPast,
          present: previous,
          future: [present, ...future]
        }
      }

      case 'REDO': {
        const next = future[0]
        const newFuture = future.slice(1)

        return {
          past: [...past, present],
          present: next,
          future: newFuture
        }
      }

      default: {
        const newPresent = reducer(present, action)

        if (present === newPresent) {
          return state
        }

        return {
          past: [...past, present],
          present: newPresent,
          future: []
        }
      }
    }
  }
}

Using it

You write your reducer like normal:

function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [...state, action.text]
    default:
      return state
  }
}

Then wrap it:

const undoableTodos = undoable(todos)

And now it supports undo and redo out of the box:

store.dispatch({ type: 'ADD_TODO', text: 'Use Redux' })
store.dispatch({ type: 'ADD_TODO', text: 'Implement Undo' })
store.dispatch({ type: 'UNDO' })

One small gotcha

Since your state is now wrapped, you’ll need to access state.present instead of state.

You can also use:

  • past.length to know if undo is possible
  • future.length to know if redo is possible

Why this is nice

What I like about this approach is how composable it is. You can choose which reducers need undo and layer this on top without changing your existing logic.

Your original reducer stays untouched, and undo/redo becomes something you add, not something you bake in.

Also, if you don’t want to implement this yourself, redux-undo already does exactly this.

This article is heavily inspired by the official Redux documentation, so I’d definitely recommend checking that out as well.

In the next part, I’ll go into the approach I actually ended up using, and why it worked better for my setup. I haven’t written it yet, but I’ll link it here when I do.

Thanks for reading
Until next time, 👋

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Generic Undo Manager for React - Part 1

Thematisch verwandte Begriffe: Generic, Undo, Manager, React  Part 1 · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-93956 | A flaw has been found in olivier-ls PHP-FTS up to 1.1.2. Affected by thi…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick