Search code examples
reactjsreduxredux-toolkit

redux-undo that wraps all slices in RTK?


I am implementing redux-undo library introduced in redux docs in my RTK project. The example in the docs guides you to wrap single slice (or reducer) to make it 'undoable'.

// todos.js
import undoable from 'redux-undo'

/* ... */

const todos = (state = [], action) => {
  /* ... */
}

const undoableTodos = undoable(todos)

export default undoableTodos
import { combineReducers } from 'redux'
import todos from './todos'
import visibilityFilter from './visibilityFilter'

const todoApp = combineReducers({
  todos,
  visibilityFilter
})

export default todoApp

You may wrap one or more reducers in undoable at any level of the reducer composition hierarchy. We choose to wrap todos instead of the top-level combined reducer so that changes to visibilityFilter are not reflected in the undo history.

This example, as described above, only restores changes in todos slice. Anything happened to visibilityFilter is not undoable. What I want is to wrap the entire store with undoable() so that with one undo() function call, you can revoke all changes to the store.

Below is my attempt in redux toolkit and I want to know if this is the right way to go.

import { configureStore } from "@reduxjs/toolkit";
import undoable from 'redux-undo'

import todoSlice from "../features/todo/todoSlice";
import visibilityFilterSlice from "../features/visibilityFilter/visibilityFilterSlice";

const store = configureStore({
  reducer: {
    todos: todoSlice,
    visibilityFilter: visibilityFilterSlice,
  },
});

export default undoable(store);

Solution

  • No, your attempt wraps the store instance, not a reducer - redux-undo won't know what to make of that. Try this instead (using combineReducers with RTK is totally fine):

    const rootReducer = combineReducers({
        todos: todoSliceReducer,
        visibilityFilter: visibilityFilterSliceReducer,
      })
    
    const undoableRootReducer = undoable(rootReducer)
    
    const store = configureStore({
      reducer: undoableRootReducer,
    });
    

    For TypeScript it is important not to do reducer: undoable(rootReducer),, but to do this in a variable declaration above the configureStore call.