Skip to content

Instantly share code, notes, and snippets.

@johanquiroga
Last active December 14, 2023 08:52
Show Gist options
  • Save johanquiroga/cbbfc0da2e9f11d2dbfd15acc4db6fc0 to your computer and use it in GitHub Desktop.
Save johanquiroga/cbbfc0da2e9f11d2dbfd15acc4db6fc0 to your computer and use it in GitHub Desktop.
Undo/Redo capability for any reducer using react hook `useReducer`
import { useReducer } from 'react';
const useUndoReducer = (reducer, initialState) => {
const undoState = {
past: [],
present: initialState,
future: []
};
const undoReducer = (state, action) => {
const newPresent = reducer(state.present, action);
if (action.type === useUndoReducer.types.undo) {
const [newPresent, ...past] = state.past;
return {
past,
present: newPresent,
future: [state.present, ...state.future]
};
}
if (action.type === useUndoReducer.types.redo) {
const [newPresent, ...future] = state.future;
return {
past: [state.present, ...state.past],
present: newPresent,
future
};
}
return {
past: [state.present, ...state.past],
present: newPresent,
future: []
};
};
return useReducer(undoReducer, undoState);
};
useUndoReducer.types = {
undo: 'UNDO',
redo: 'REDO'
};
export default useUndoReducer;
// Example
/* import React, { useReducer } from "react";
import useUndoReducer from "./useUndoReducer";
const initialState = {}
const reducer = (state = initialState, action) => {
// Your reducer
return state;
};
const YourComponent = (props) => {
const [state, dispatch] = useUndoReducer(reducer, initialState);
// Some actions
const someAction = useCallback(
(payload) => {
dispatch({
type: 'SOME_ACTION',
payload,
});
},
[dispatch]
);
// Undo/Redo actions
const undo = useCallback(() => {
dispatch({ type: useUndoReducer.types.undo });
}, [dispatch]);
const redo = useCallback(() => {
dispatch({ type: useUndoReducer.types.redo });
}, [dispatch]);
// render or do something something
// ...
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment