Undo and Redo with useReducer
Implement an undo and redo functionality for a text editor by using useReducer to manage state history and control state changes.
import React, { useReducer } from 'react';
// Action Types
const ACTION_TYPES = {
CHANGE: 'CHANGE',
UNDO: 'UNDO',
REDO: 'REDO'
};
// Reducer to handle actions
const reducer = (state, action) => {
const { past, present, future } = state;
switch (action.type) {
case ACTION_TYPES.CHANGE:
return {
past: [...past, present],
present: action.newText,
future: []
};
case ACTION_TYPES.UNDO:
if (past.length === 0) return state;
return {
past: past.slice(0, -1),
present: past[past.length - 1],
future: [present, ...future]
};
case ACTION_TYPES.REDO:
if (future.length === 0) return state;
return {
past: [...past, present],
present: future[0],
future: future.slice(1)
};
default:
return state;
}
};
const initialState = { past: [], present: '', future: [] };
Defines the initial state and reducer function, action types and handler logic for change, undo, and redo actions.
const App = () => {
const [state, dispatch] = useReducer(reducer, initialState);
const { past, present, future } = state;
const handleChange = (newText) => {
dispatch({ type: ACTION_TYPES.CHANGE, newText });
};
const handleUndo = () => {
dispatch({ type: ACTION_TYPES.UNDO });
};
const handleRedo = () => {
dispatch({ type: ACTION_TYPES.REDO });
};
return (
<div>
<button onClick={handleUndo} disabled={past.length === 0}>Undo</button>
<button onClick={handleRedo} disabled={future.length === 0}>Redo</button>
<textarea value={present} onChange={(e) => handleChange(e.target.value)} />
</div>
);
};
export default App;
The App component sets up the useReducer hook with the reducer and initial state. It provides event handlers to change the text, undo and redo changes.