How do you implement an undo/redo system in React?

Answer

An undo/redo system requires storing a history of states. Using useReducer with a history stack: type HistoryState<T> = { past: T[]; present: T; future: T[] };. The reducer handles normal actions by pushing the current present to past, setting the new state as present, and clearing future. UNDO: pop from past, push present to future, set popped as present. REDO: pop from future, push present to past, set popped as present. Implement as a custom hook: function useHistory<T>(initialState: T) { const [state, dispatch] = useReducer(historyReducer, { past: [], present: initialState, future: [] }); const undo = () => dispatch({ type: "UNDO" }); const redo = () => dispatch({ type: "REDO" }); return { state: state.present, undo, redo, canUndo: state.past.length > 0, canRedo: state.future.length > 0 }; }. Optimizations: limit history length to prevent memory growth; use Immer for efficient state updates with structural sharing (unchanged parts of the state tree share references); debounce rapid changes (text input) to avoid storing every keystroke. Libraries like Redux Toolkit with redux-undo or Zustand with immer middleware handle this pattern well.