Skip to content

Instantly share code, notes, and snippets.

@azu
Created September 29, 2021 06:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save azu/3f5cd0ed03b4482ee287d7e5539482f4 to your computer and use it in GitHub Desktop.
Save azu/3f5cd0ed03b4482ee287d7e5539482f4 to your computer and use it in GitHub Desktop.
Undo/Redo Manage implementation using React Hooks: https://twitter.com/azu_re/status/1443105296994340867
type HistoryState = unknown; /* state object */
const useHistoryState = (defaultState: HistoryState) => {
const STACK_SIZE_LIMIT = 20;
const [currentState, setCurrentState] = useState<HistoryState>(defaultState);
const [undoStack, setUndoStack] = useState<HistoryState[]>([]);
const [redoStack, setRedoStack] = useState<HistoryState[]>([]);
const canUndo = useMemo(() => undoStack.length > 0, [undoStack.length]);
const canRedo = useMemo(() => redoStack.length > 0, [redoStack.length]);
const pushState = useCallback((item: HistoryState) => {
setCurrentState(item);
setUndoStack(prevState => prevState.concat(item).slice(-STACK_SIZE_LIMIT));
setRedoStack([]);
}, []);
const undo = useCallback(() => {
const popItem = undoStack.pop();
if (popItem) {
setCurrentState(popItem);
setRedoStack(prevState => prevState.concat(popItem));
}
}, [undoStack]);
const redo = useCallback(() => {
const popItem = redoStack.pop();
if (popItem) {
setCurrentState(popItem);
}
}, [redoStack]);
return [
{ currentState, canUndo, canRedo },
{ undo, redo, pushState },
] as const;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment