Home

Awesome

use-travel

Node CI Coverage Status npm license

A React hook for state time travel with undo, redo, reset and archive functionalities.

Motivation

use-travel is a small and high-performance library for state time travel. It's built on Mutative to support mutation updating immutable data. It's designed to be simple and easy to use, and it's also customizable for different use cases.

It's suitable for building any time travel feature in your application.

Installation

npm install use-travel mutative
# or
yarn add use-travel mutative

Features

Example

API

You can use useTravel to create a time travel state. And it returns a tuple with the current state, the state setter, and the controls. The controls include back(), forward(), reset(), canBack(), canForward(), canArchive(), getHistory(), patches, position, archive(), and go().

import { useTravel } from 'use-travel';

const App = () => {
  const [state, setState, controls] = useTravel(0, {
    maxHistory: 10,
    initialPatches: {
      patches: [],
      inversePatches: [],
    },
  });
  return (
    <div>
      <div>{state}</div>
      <button onClick={() => setState(state + 1)}>Increment</button>
      <button onClick={() => setState(state - 1)}>Decrement</button>
      <button onClick={() => controls.back()} disabled={!controls.canBack()}>
        Undo
      </button>
      <button
        onClick={() => controls.forward()}
        disabled={!controls.canForward()}
      >
        Redo
      </button>
      <button onClick={controls.reset}>Reset</button>
      {controls.getHistory().map((state, index) => (
        <div key={index}>{state}</div>
      ))}
      {controls.patches.patches.map((patch, index) => (
        <div key={index}>{JSON.stringify(patch)}</div>
      ))}
      <div>{controls.position}</div>
      <button
        onClick={() => {
          controls.go(1);
        }}
      >
        Go
      </button>
    </div>
  );
};

Parameters

Parametertypedescriptiondefault
maxHistorynumberThe maximum number of history to keep10
initialPatchesTravelPatchesThe initial patches{patches: [],inversePatches: []}
initialPositionnumberThe initial position of the state0
autoArchivebooleanAuto archive the statetrue

Returns

Returntypedescription
stateValue<S, F>The current state
setStateUpdater<InitialValue<S>>The state setter, support mutation update or return immutable data
controls.back(amount?: number) => voidGo back to the previous state
controls.forward(amount?: number) => voidGo forward to the next state
controls.reset() => voidReset the state to the initial state
controls.canBack() => booleanCheck if can go back to the previous state
controls.canForward() => booleanCheck if can go forward to the next state
controls.canArchive() => booleanCheck if can archive the current state
controls.getHistory() => T[]Get the history of the state
controls.patchesTravelPatches[]Get the patches history of the state
controls.positionnumberGet the current position of the state
controls.go(nextPosition: number) => voidGo to the specific position of the state
controls.archive() => voidArchive the current state(the autoArchive options should be false)

TravelPatches is the type of patches history, it includes patches and inversePatches.

If you want to control the state travel manually, you can set the autoArchive option to false, and use the controls.archive function to archive the state.

If you want to persist the state, you can use state/controls.patches/controls.position to save the travel history. Then, read the persistent data as initialState, initialPatches, and initialPosition when initializing the state, like this:

const [state, setState, controls] = useTravel(initialState, {
  initialPatches,
  initialPosition,
});

License

use-travel is MIT licensed.