undo/redo functionality with React Hooks.
yarn add use-undo
import React from 'react';
import ReactDOM from 'react-dom';
import useUndo from 'use-undo';
const App = () => {
const [
countState,
{
set: setCount,
reset: resetCount,
undo: undoCount,
redo: redoCount,
canUndo,
canRedo,
},
] = useUndo(0);
const { present: presentCount } = countState;
return (
<div>
<p>You clicked {presentCount} times</p>
<button key="increment" onClick={() => setCount(presentCount + 1)}>
+
</button>
<button key="decrement" onClick={() => setCount(presentCount - 1)}>
-
</button>
<button key="undo" onClick={undoCount} disabled={!canUndo}>
undo
</button>
<button key="redo" onClick={redoCount} disabled={!canRedo}>
redo
</button>
<button key="reset" onClick={() => resetCount(0)}>
reset to 0
</button>
</div>
);
};
Manual checkpoints are helpful also when you want manual control over checkpoints. For example it is more helpful when you want to handle input type html tag where value needs to be handled alongside the undo and redo functionality should be handled over some conditions.
import React from 'react';
import ReactDOM from 'react-dom';
import useUndo from 'use-undo';
const App = () => {
const [
countState,
{
set: setCount,
reset: resetCount,
undo: undoCount,
redo: redoCount,
canUndo,
canRedo,
},
] = useUndo(0, { useCheckpoints: true });
const { present: presentCount } = countState;
return (
<div>
<p>You clicked {presentCount} times</p>
<button key="increment" onClick={() => setCount(presentCount + 1, true)}>
WithCheckpoint+
</button>
<button key="decrement" onClick={() => setCount(presentCount - 1, true)}>
WithCheckpoint-
</button>
<button key="increment" onClick={() => setCount(presentCount + 1)}>
NoCheckpoint+
</button>
<button key="decrement" onClick={() => setCount(presentCount - 1)}>
NoCheckpoint-
</button>
<button key="undo" onClick={undoCount} disabled={!canUndo}>
undo
</button>
<button key="redo" onClick={redoCount} disabled={!canRedo}>
redo
</button>
<button key="reset" onClick={() => resetCount(0)}>
reset to 0
</button>
</div>
);
};
const [state, actions] = useUndo(initialState);
Key | Type | Description |
---|---|---|
past | Array |
The undo stack. |
present | Any |
The present state. |
future | Array |
The redo stack. |
Key | Type | Description |
---|---|---|
set | function |
Assign a new value to present . |
reset | function |
Clear past array and future array. Assign a new value to present . |
undo | function |
See handling-undo. |
redo | function |
See handling-redo. |
canUndo | boolean |
Check whether state.undo.length is 0 . |
canRedo | boolean |
Check whether state.redo.length is 0 . |
Refer to Redux Implementing Undo History, use-undo
implements the same concect with useReducer
.
The state structure looks like:
{
past: Array<T>,
present: <T>,
future: Array<T>
}
It stores all states we need. To operate on this state, there are three functions in actions
(set
, undo
and redo
) that dispatch defined types and necessary value.
MIT © homerchen19