Search code examples
reactjsreduxredux-toolkit

after replacing redux state, actions don't work anymore


I have an issue in redux-toolkit. What I am trying to do is to save the state of a redux as a snapshot file and load this state later with the help of replaceReducer function.

currently my state gets loaded but I have a problem with actions. they don't work anymore after new state is loaded what seems to be the problem?

store.js

import { configureStore, combineReducers } from '@reduxjs/toolkit';

import infoReducer from '../features/renderer/rendererSlice';
import cameraReducer from '../features/camera/cameraSlice';
import modalsreducer from '../features/modal/modalSlice';
import globalsReducer from '../features/global/globalsSlice';
import treeReducer from '../features/tree/treeSlice';
import modelReducer from '../features/model/modelSlice';
import eventReducer from '../features/event/eventSlice';

export const rootReducer = combineReducers({
  globals: globalsReducer,
  renderer: infoReducer,
  camera: cameraReducer,
  modal: modalsreducer,
  tree: treeReducer,
  model: modelReducer,
  event: eventReducer,
});

const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false }),
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

export default store;

snapModal.tsx

 const handleSaveSnapshot = (): void => {
    onClose(false);
    const state = store.getState();
    console.log(state)
    const stateJSON = JSON.stringify(state);
    const blob = new Blob([stateJSON], { type: 'application/json' });
    const timestamp = new Date().toISOString();
    const filename = `${timestamp}-tracer-snapshot.json`;
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = filename;
    link.click();
    URL.revokeObjectURL(url);
  };

  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
    const file = event.target.files?.[0];
    if (file) {
      const reader = new FileReader();
      reader.onload = (): void => {
        const stateJSON = reader.result as string;
        const newState = JSON.parse(stateJSON);
        store.replaceReducer(() => newState);
      };
      reader.readAsText(file);
    }
    event.target.value = '';
  };

Solution

  • store.replaceReducer is most likely the wrong approach for this. It's documented as a way to do code-splitting because it replaces the root reducer whereas you want to load state from a json file into the existing reducers if I understood it correctly.

    I'd look into https://redux-toolkit.js.org/api/configureStore#preloadedstate and create a function that can re-initialize the store with preloadedState. An alternative would be to search for a middleware that offers file-based state loading.