Skip to content

Instantly share code, notes, and snippets.

@mtbrock
Created September 11, 2023 06:06
Show Gist options
  • Save mtbrock/84f4b35797635642e7997f2b009d13e6 to your computer and use it in GitHub Desktop.
Save mtbrock/84f4b35797635642e7997f2b009d13e6 to your computer and use it in GitHub Desktop.
React useUndoState - a hook for using state with history
import React, { useRef, useState } from "react";
function update(past, future, setState, setCanRedo, setCanUndo) {
setState(past.current[past.current.length - 1]);
setCanRedo(future.current.length > 0);
setCanUndo(past.current.length > 1);
}
export default function useUndoState(initialValue) {
const past = useRef([initialValue]);
const future = useRef([]);
const [state, setState] = useState(initialValue);
const [canUndo, setCanUndo] = useState(false);
const [canRedo, setCanRedo] = useState(false);
function undo() {
if (past.current.length === 1) {
return;
}
future.current.unshift(past.current.pop());
update(past, future, setState, setCanRedo, setCanUndo);
}
function redo() {
if (future.current.length === 0) {
return;
}
past.current.push(future.current.shift());
update(past, future, setState, setCanRedo, setCanUndo);
}
function addState(next) {
if (typeof next === "function") {
next = next(state);
}
future.current = [];
past.current.push(next);
update(past, future, setState, setCanRedo, setCanUndo);
}
const undoContext = {
undo,
redo,
canUndo,
canRedo
};
return [state, addState, undoContext];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment