Implement Undo History - Tuong-Nguyen/JavaScript-Structure GitHub Wiki

Algorithm

Shape of State

{
  past: Array<T>,
  present: T,
  future: Array<T>
}

Handling Actions

UNDO

  • Remove last element from past
  • Set present to removed element in previous step
  • Insert old present at the beginning of future

REDO

  • Remove first element from future
  • Set present to removed element in previous step
  • Insert old present at the end of past

Others

  • Insert present at the end of past
  • Set present to the new state after handling the action
  • Clear the future

Using Redux Undo

Redux Undo is a library that provides simple Undo and Redo functionality for any part of Redux tree

Installation

npm install --save redux-undo

Usage

Wrap reducer with undoable reducer enhancer

import undoable, { distinctState } from 'redux-undo'

/* ... */

const todos = (state = [], action) => {
  /* ... */
}

const undoableTodos = undoable(todos, {
  filter: distinctState()
})

export default undoableTodos

combineReducers()

  • combineReducers not changed but the original reducer will now refer to enhanced reducer
  • Note: undoable can wrap one or more reducers at any level.

Update the Selectors

Now state looks like

{
  visibilityFilter: 'SHOW_ALL',
  todos: {
    past: [
      [],
      [{ text: 'Use Redux' }],
      [{ text: 'Use Redux', complete: true }]
    ],
    present: [
      { text: 'Use Redux', complete: true },
      { text: 'Implement Undo' }
    ],
    future: [
      [
        { text: 'Use Redux', complete: true },
        { text: 'Implement Undo', complete: true }
      ]
    ]
  }
}
  • state.todos -> state.todos.present

Add Actions

  • Import ActionCreators from redux-undo
import { ActionCreators as UndoActionCreators } from 'redux-undo'
  • Undo action creator: UndoActionCreators.undo()
  • Redo action creator: UndoActionCreators.redo()