JAVASCRIPT
Implement Undo/Redo Functionality with useUndoRedo
A React hook that enables easy undo and redo capabilities for any piece of state, managing a history of changes for interactive applications like editors or drawing tools.
import { useState, useCallback } from 'react';
const useUndoRedo = (initialState) => {
const [past, setPast] = useState([]);
const [present, setPresent] = useState(initialState);
const [future, setFuture] = useState([]);
const set = useCallback((newState) => {
if (newState === present) return;
setPast(prevPast => [...prevPast, present]);
setPresent(newState);
setFuture([]);
}, [present]);
const undo = useCallback(() => {
if (past.length === 0) return;
const previous = past[past.length - 1];
const newPast = past.slice(0, past.length - 1);
setPast(newPast);
setPresent(previous);
setFuture(prevFuture => [present, ...prevFuture]);
}, [past, present]);
const redo = useCallback(() => {
if (future.length === 0) return;
const next = future[0];
const newFuture = future.slice(1);
setFuture(newFuture);
setPast(prevPast => [...prevPast, present]);
setPresent(next);
}, [future, present]);
const canUndo = past.length > 0;
const canRedo = future.length > 0;
return { present, set, undo, redo, canUndo, canRedo };
};
export default useUndoRedo;
/*
// Example Usage:
function DrawingApp() {
const { present, set, undo, redo, canUndo, canRedo } = useUndoRedo('');
return (
<div>
<input
type="text"
value={present}
onChange={(e) => set(e.target.value)}
/>
<button onClick={undo} disabled={!canUndo}>Undo</button>
<button onClick={redo} disabled={!canRedo}>Redo</button>
<p>Current: {present}</p>
</div>
);
}
*/
How it works: The `useUndoRedo` hook provides a flexible way to add undo and redo capabilities to any state in a React component. It manages three arrays: `past` (previous states), `present` (current state), and `future` (states that were undone and can be redone). The `set` function updates the `present` state and pushes the old `present` to `past`, clearing `future`. `undo` moves the `present` to `future` and restores the last `past` state, while `redo` reverses this operation. `canUndo` and `canRedo` booleans help manage button disabled states.