redux-dynamic-modules icon indicating copy to clipboard operation
redux-dynamic-modules copied to clipboard

Reset redux store on specific action

Open CharlesMcD opened this issue 7 years ago • 11 comments

I try to reset the redux store (logout behavior) but I can't find a simple solution that allows me to do it globally when using redux-dynamic-modules. Before using redux-dynamic-modules, I used to do what Dan was proposing here with the combineReducer function. https://stackoverflow.com/a/35641992/6765022 Now I understand that we have to send a map of reducers to the createStore function that will take care of everything. Therefore, I cannot intercept the creation of the reducers to listen to a logout action. Anyone have any idea how to implement this behavior?

CharlesMcD avatar Apr 18 '19 00:04 CharlesMcD

What do you mean by reset redux store? If you want to reset state(s) to some "default" value you can catch "logout" action in all the reducers that control the states you want to reset. If you want to unload some modules from redux store you should unmount (in other words stop render) components that loaded modules via DynamicModuleLoader

abdurahmanus avatar Apr 23 '19 06:04 abdurahmanus

I mean reset the store to its default value. Obviously it is possible to listen in all reducers, but I was looking for a solution to only have to add a "custom" case when creating the store as it is possible to do easily without this library. Normally I could do something like that :

const appReducer = combineReducers({
  /* your app’s top-level reducers */
})

const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    state = undefined
  }

  return appReducer(state, action)
}

but not anymore since I have to provide a map of reducers that have not yet been "combined" together with combineReducers.

export const getRootModule: ISagaModule<ApplicationState> = {
  id: 'root',
  reducerMap: myReducerMap as any,     <-- Here, I have to provide a list of reducers
  sagas: [rootSaga],
};

And myReducerMap looks like this

export const myReducerMap = {
  router: connectRouter(history),  
  authentication: authenticationReducer,
  userPictures: userPictureReducer,
  pictureUploader: pictureUploaderReducer,
  // other reducers...
};
```

CharlesMcD avatar Apr 23 '19 15:04 CharlesMcD

you can describe your module like this:

function getModule1() {
  return {
    id: "module1",
    reducerMap: {
      module1: module1Reducer // only one key in map
    }
  }
}

and then you could use combineReducers or whatever to create module1Reducer. Inside module1Reducer you could reset state as you did before. If you want to reset state of 2 separate modules you should do it in 2 separate reducers because they control separate state.

abdurahmanus avatar Apr 24 '19 07:04 abdurahmanus

@CharlesMcD Have you figured out how to do this? @abdurahmanus I think what you said makes sense. But currently I'm converting a monolithic redux store to dynamic modules step by step. I need this one call that reset all my registered root level keys to default value without adding a new key. Is this possible? What's the correct way to do it?

ryanf5 avatar Jun 18 '19 20:06 ryanf5

I never really found the solution I was looking for to my problem. The walkaround is used was to listen in each reducer for the "logout" action. It was a small project so it's not that bad, but I understand that it can be a pain in the ass in a big project. I didn't really understood @abdurahmanus last solution because I couldn't use combineReducers function to generate the "module1Reducer" from his example. I absolutely had to provide a list of reducer to the "reducerMap" key.

CharlesMcD avatar Jun 18 '19 21:06 CharlesMcD

@CharlesMcD What he meant was to create a new key on top of the gaint object, like module1: module1Reducer here the module1Reducer is your rootReducer from:

const appReducer = combineReducers({
  /* your app’s top-level reducers */
})

const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    state = undefined
  }

  return appReducer(state, action)
}

In this way you can reset all in your original myReducerMap but you'll make it one level deeper. combineReducer works like https://github.com/microsoft/redux-dynamic-modules/blob/master/packages/todo-example/src/modules/shoppinglist/reducers/index.js

@navneet-g @abettadapur Idea on how to reset whole state besides each module implement its own logout? Use case is when user logout, we want to reset all modules to initialState... This is the only blocker right now...

ryanf5 avatar Jun 18 '19 22:06 ryanf5

One idea is that you could recreate the store entirely, through some side-effect, but that doesn't seem like a great solution.

Honestly, I think this is just a limitation of our library, because we do not support nested modules. @navneet-g Do you think there is a way we could support this usecase?

abettadapur avatar Jun 20 '19 02:06 abettadapur

How about adding a reducer to the moduleStoreSettings that can act on the overall store state? This would also help with #58 and other cases where enhancers depend on reducers being in place.

dbartholomae avatar Aug 23 '19 01:08 dbartholomae

Sorry I missed it, I will take a look soon.

navneet-g avatar Aug 23 '19 01:08 navneet-g

You can send a custom advancedCombineReducers to ModuleStore, and wrap the reducer with reset action, something similar to idea described in https://alligator.io/redux/reset-state-redux/

navneet-g avatar Aug 23 '19 01:08 navneet-g

This is really easy @CharlesMcD @ryanf5. Like @navneet-g suggested:

const store = createDynamicStore({
        // initialState: { },
        // extensions,
        advancedCombineReducers: combineReducersWithReset
    },
    /* core modules */
);

and

import { combineReducers } from 'redux';

const combineReducersWithReset = (...args)  => {
    const rootReducer = combineReducers(...args);
    return (state, action) => {
        if (action.type === LOGOUT)
            return rootReducer({}, action);
        return rootReducer(state, action);
    }
};

adroste avatar Jul 22 '20 17:07 adroste