DEV Community

Cover image for ๐Ÿš€ New React Challenge: Undo / Redo
ReactChallenges
ReactChallenges

Posted on Originally published at reactchallenges.com

๐Ÿš€ New React Challenge: Undo / Redo

Most apps let users make changes but never let them take them back. This challenge is about building the mechanism that changes everything: a history you can rewind.


๐Ÿงฉ Overview

Build a notes editor whose add, edit, toggle, and delete actions are tracked in a useReducer past/present/future history, so every change can be undone and redone with buttons or keyboard shortcuts.

๐Ÿ‘‰ https://www.reactchallenges.com/challenges/undo-redo


โœ… Requirements

  • The list starts with the notes "Buy groceries" and "Walk the dog".
  • Each note is editable through an input.
  • Each note has a done toggle and a delete button.
  • Undo and redo are disabled on first render.
  • Adding a note appends it to the list and clears the new-note field.
  • A change enables undo; undoing restores the previous list, disables undo when there is nothing left to undo, and enables redo.
  • Redo reapplies an undone change and disables itself once there is nothing left to redo.
  • Adding, editing, toggling, and deleting a note can each be undone.
  • An undone change can be redone.
  • Consecutive edits to the same note collapse into a single undo step.
  • An edit that does not change the text is ignored and adds no history.
  • Adding an empty or whitespace-only note is ignored and adds no history.
  • Undo is triggered by Cmd/Ctrl+Z.
  • Redo is triggered by Shift+Ctrl+Z.
  • Pressing undo with no history or redo with nothing to redo leaves the list unchanged.
  • The status line reports how many undo and redo steps are available.
  • New notes always get unique identifiers, even after undoing and adding again.
  • Making a new change after undoing clears the redo stack.

๐Ÿ’ก Notes

  • The history shape most people reach for is { past, present, future }: present is what renders, while past and future are stacks of snapshots.
  • Return the same state object for a no-op (a blank note, an edit that doesn't change the text, undo/redo with an empty stack) so React bails out and history stays clean.
  • Keep the id counter outside the history โ€” rewinding it on undo would let two different notes share an id.

๐Ÿงช Tests

  1. renders the initial notes
  2. disables undo and redo on load
  3. adds a note and clears the input
  4. enables undo after a change and disables it again after undoing
  5. redoes an undone change
  6. undoes a deletion and restores the note
  7. undoes a toggle and restores the previous state
  8. undoes an edit and restores the previous text
  9. collapses continuous edits to one note into a single undo step
  10. ignores an edit that does not change the text
  11. does not push history when adding an empty note
  12. does not push history when adding a whitespace-only note
  13. undoes with Ctrl+Z
  14. undoes with Cmd+Z
  15. redoes with Shift+Ctrl+Z
  16. does nothing when undo is pressed with no history
  17. does nothing when redo is pressed with no future
  18. reports the available undo and redo steps
  19. keeps note identifiers unique after undo and redo
  20. clears the redo stack when a new change is made

Work through it and you'll come away knowing how to model reversible state with a reducer โ€” a skill that shows up everywhere from text editors to form builders to drag-and-drop canvases.

๐Ÿ”ฅ Start the Challenge Now

Top comments (0)