redux-live-undo

0.1.1 • Public • Published

redux-live-undo

A generic, high-order reducer that allows you to transparently add undo/redo functionality on top of other redux reducers. redux-live-undo allows state to be updated as users type without creating undo steps for every state change.

CircleCI

Inspired by the omnidan's work on redux-undo, redux-live-undo provides a simpler interface with admittedly less options but more flexibility. Most importantly, redux-live-undo has the concept of "history checkpoints" that allow you to dispatch actions without making every change to the state a step in the undo history.

For example, this allows you live updating of UI state (such as in a text input) without creating an undo step for every single keypress.

redux-live-undo also allows you to track entire sections of your application state as a single history so undo/redo actions can be synced across various types of data.

Brief Overview

redux-live-undo tracks a history of state of its sub-reducers. The state returned by redux-live-undo has this shape:

  • present: the current state of the sub-reducers.
  • past: an array of past state checkpoints, ordered from oldest to newest.
  • future: an array of future state checkpoints, order from newest to oldest. Only populated after an undo or redo.

Note: New history checkpoints are only recorded when the action dispatched has the undoableHistoryCheckpoint property set to true and changeDetector returns true.

Reducers can optionally provide a changeDetector function to override what changes are allowed to be checkpointable.

Action flags

Flags on actions can affect the behavior of the undo history state:

  • undoableHistoryCheckpoint: Marks when the next state should be considered a checkpoint in the undo history
  • undoableIrreversibleCheckpoint: Marks when the next state should clear any undo history. Typically used if related state in another system (eg. a backend service) cannot be reversed.

Example Usage

Given a simple reducer that tracks the state of a string:

const TEXT_UPDATE = 'TEXT_UPDATE';
 
function StringReducer(state = '', action = {}) {
  switch (action.type) {
    case TEXT_UPDATE:
      return action.value;
    default:
      return state;
  }
}

Use redux-live-undo to add reducer functionality:

import Undoable from 'redux-live-undo';
 
const rootReducer = Undoable({
  string: StringReducer
});

When passed to combinedReducers, you will have access to present, past, and future states:

import { createStore } from 'redux';
 
const store = createStore(rootReducer);
store.getState();
// => {
//   past: [''],
//   present: {
//     string: ''
//   },
//   future: []
// }

Dispatch an update as an input changes:

store.dispatch({
  type: TEXT_UPDATE,
  value: 'H'
});
 
store.getState();
// => {
//   past: [''],
//   present: {
//     string: 'H'
//   },
//   future: []
// }

Dispatch an update with a checkpoint when you want a snapshot to jump back to, for example, when the input blurs:

store.dispatch({
  type: TEXT_UPDATE,
  value: 'Hi',
  undoableHistoryCheckpoint: true
});
 
store.getState();
// => {
//   past: ['', 'Hi'],
//   present: {
//     string: 'Hi'
//   },
//   future: []
// }

Undo to the last checkpoint:

import { UNDO } from 'redux-live-undo';
 
store.dispatch({
  type: UNDO
});
 
store.getState();
// => {
//   past: [''],
//   present: {
//     string: ''
//   },
//   future: ['Hi']
// }

Redo the action:

import { REDO } from 'redux-live-undo';
 
store.dispatch({
  type: REDO
});
 
store.getState();
// => {
//   past: ['', 'Hi'],
//   present: {
//     string: 'Hi'
//   },
//   future: []
// }

Credits

  • @joshdover
  • @tornstrom

Readme

Keywords

Package Sidebar

Install

npm i redux-live-undo

Weekly Downloads

48

Version

0.1.1

License

MIT

Last publish

Collaborators

  • joshdover