I am trying to deal with the problem, addressed, in general in an earlier thread - How to reset the state of a Redux store? - the need to reinitialize/invalidate the entire redux store on user logout.
In my case, however, something is still missing. I am using Redux with ConnectedRouter and I tried to do the following.
Define the rootReducer as:
export default history =>
combineReducers({
router: connectRouter(history),
user,
manager,
vendor
// rest of your reducers
});
Then I do configureStore
, importing the above as createRootReducer
:
const configureStore = (initialState = {}, history) => {
let composeEnhancers = compose;
const composeWithDevToolsExtension =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
const enhancers = [];
const middleware = [sagaMiddleware, thunk, routerMiddleware(history)];
if (typeof composeWithDevToolsExtension === 'function') {
composeEnhancers = composeWithDevToolsExtension;
}
const store = createStore(
createRootReducer(history), // root reducer with router state
initialState,
composeEnhancers(applyMiddleware(...middleware), ...enhancers)
);
store.runSaga = sagaMiddleware.run;
store.subscribe(() => {
const state = store.getState();
const { session } = state['user'];
if (!session) {
console.log('no valid session');
initialState = undefined;
} else {
const { token } = session;
const decodedToken = jwt_decode(token);
const { exp } = decodedToken;
const now = new Date();
if (exp > now.getTime()) {
console.warn('token expired');
initialState = undefined;
} else {
console.log('token valid');
}
}
});
return store;
};
export default configureStore({}, history);
The idea is that initialState = undefined;
should reset my state. It is not working for me though.
Where would be the correct place to do this, given that I am using the ConnectedRouter
and passing the history
object to it?
I am trying to deal with the problem, addressed, in general in an earlier thread - How to reset the state of a Redux store? - the need to reinitialize/invalidate the entire redux store on user logout.
In my case, however, something is still missing. I am using Redux with ConnectedRouter and I tried to do the following.
Define the rootReducer as:
export default history =>
combineReducers({
router: connectRouter(history),
user,
manager,
vendor
// rest of your reducers
});
Then I do configureStore
, importing the above as createRootReducer
:
const configureStore = (initialState = {}, history) => {
let composeEnhancers = compose;
const composeWithDevToolsExtension =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
const enhancers = [];
const middleware = [sagaMiddleware, thunk, routerMiddleware(history)];
if (typeof composeWithDevToolsExtension === 'function') {
composeEnhancers = composeWithDevToolsExtension;
}
const store = createStore(
createRootReducer(history), // root reducer with router state
initialState,
composeEnhancers(applyMiddleware(...middleware), ...enhancers)
);
store.runSaga = sagaMiddleware.run;
store.subscribe(() => {
const state = store.getState();
const { session } = state['user'];
if (!session) {
console.log('no valid session');
initialState = undefined;
} else {
const { token } = session;
const decodedToken = jwt_decode(token);
const { exp } = decodedToken;
const now = new Date();
if (exp > now.getTime()) {
console.warn('token expired');
initialState = undefined;
} else {
console.log('token valid');
}
}
});
return store;
};
export default configureStore({}, history);
The idea is that initialState = undefined;
should reset my state. It is not working for me though.
Where would be the correct place to do this, given that I am using the ConnectedRouter
and passing the history
object to it?
- have you tried dispatching an action to the reducer to set the state undefined and then logout ? – Pranay Tripathi Commented Jan 15, 2019 at 13:30
2 Answers
Reset to default 17I wanted to point out to a couple of things that are pretty important before I give you a solution:
When using redux you should never attempt to alter the state of your store directly. The state should always change through the reducer as a reaction to an action. Therefore, reassigning the parameter
initialState
inside thatsubscribe
callback is incorrect and pointless.I don't think that you want to "reset" the state of the
router
property, correct?
One way to solve this is to use a reducer enhancer, something like this:
const resetEnhancer = rootReducer => (state, action) => {
if (action.type !== 'RESET') return rootReducer(state, action);
const newState = rootReducer(undefined, {});
newState.router = state.router;
return newState;
};
And then when you create your store do this:
const store = createStore(
resetEnhancer(createRootReducer(history)),
initialState,
composeEnhancers(applyMiddleware(...middleware), ...enhancers)
);
And in that subscribe
callback do this:
if (!session) {
store.dispatch({type: 'RESET'});
}
One last extra-tip: since you are using redux-saga
I strongly suggest that you move what you are doing inside that subscribe
callback into a saga.
You can make an action for clearing the store and use it in your rootReducer
as like this:
const appReducer = combineReducers({
... // your reducers
});
const rootReducer = (state, action) => {
if (action.type === 'CLEAR_STORE') return appReducer(undefined, action);
return appReducer(state, action);
};
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export const configureStore = (initialState, history) =>
createStore(
connectRouter(history)(rootReducer),
initialState,
composeEnhancers(applyMiddleware(routerMiddleware(history), thunkMiddleware))
);
You'll have appReducer
with all your reducers but also rootReducer
which will be the function that will determinate returning a corresponding value or an undefined one.
TIP: You can use your Logout action rather than using a new action just for clearing the store