我正在使用Redux进行状态管理。 如何将存储重置为初始状态?
例如,假设我有两个用户帐户(u1和u2)。 想象下面的一系列事件:
用户u1登录到应用程序并做了一些事情,所以我们在存储中缓存一些数据。 用户u1退出。 用户u2无需刷新浏览器即可登录应用。
此时,缓存的数据将与u1关联,我想清理它。
当第一个用户注销时,如何将Redux存储重置为初始状态?
我正在使用Redux进行状态管理。 如何将存储重置为初始状态?
例如,假设我有两个用户帐户(u1和u2)。 想象下面的一系列事件:
用户u1登录到应用程序并做了一些事情,所以我们在存储中缓存一些数据。 用户u1退出。 用户u2无需刷新浏览器即可登录应用。
此时,缓存的数据将与u1关联,我想清理它。
当第一个用户注销时,如何将Redux存储重置为初始状态?
当前回答
只是对@dan-abramov答案的扩展,有时我们可能需要保留某些被重置的键。
const retainKeys = ['appConfig'];
const rootReducer = (state, action) => {
if (action.type === 'LOGOUT_USER_SUCCESS' && state) {
state = !isEmpty(retainKeys) ? pick(state, retainKeys) : undefined;
}
return appReducer(state, action);
};
其他回答
另一种选择是:
store.dispatch({type: '@@redux/INIT'})
'@@redux/INIT'是redux自动调度的动作类型,当你创建存储时,所以假设你的reducers都有一个默认值,这将被那些捕获,并开始你的状态新鲜。不过,它可能被认为是redux的私有实现细节,所以买家要小心……
一种方法是在应用程序中编写一个根减速器。
根减速机通常会将处理操作委托给combineReducers()生成的减速机。但是,无论何时它接收到USER_LOGOUT操作,它都会再次返回初始状态。
例如,如果你的根减速器是这样的:
const rootReducer = combineReducers({
/* your app’s top-level reducers */
})
你可以将它重命名为appReducer,并编写一个新的rootReducer委托给它:
const appReducer = combineReducers({
/* your app’s top-level reducers */
})
const rootReducer = (state, action) => {
return appReducer(state, action)
}
现在我们只需要教新的rootReducer返回初始状态以响应USER_LOGOUT操作。如我们所知,无论操作如何,当调用以undefined作为第一个参数时,约简器都应该返回初始状态。让我们用这个事实来有条件地剥离累积状态,当我们把它传递给appReducer:
const rootReducer = (state, action) => {
if (action.type === 'USER_LOGOUT') {
return appReducer(undefined, action)
}
return appReducer(state, action)
}
现在,每当USER_LOGOUT触发时,所有减约器都将重新初始化。它们还可以返回与初始值不同的值,因为它们可以检查动作。也要打字。
重申一下,完整的新代码是这样的:
const appReducer = combineReducers({
/* your app’s top-level reducers */
})
const rootReducer = (state, action) => {
if (action.type === 'USER_LOGOUT') {
return appReducer(undefined, action)
}
return appReducer(state, action)
}
如果使用redux-persist,可能还需要清理存储空间。Redux-persist将您的状态副本保存在存储引擎中,刷新时将从那里加载状态副本。
首先,您需要导入适当的存储引擎,然后在将其设置为undefined并清除每个存储状态键之前解析状态。
const rootReducer = (state, action) => {
if (action.type === SIGNOUT_REQUEST) {
// for all keys defined in your persistConfig(s)
storage.removeItem('persist:root')
// storage.removeItem('persist:otherKey')
return appReducer(undefined, action);
}
return appReducer(state, action);
};
丹·阿布拉莫夫的回答帮我破案了。然而,我遇到了一个案例,并不是整个州都需要清理。所以我是这样做的:
const combinedReducer = combineReducers({
// my reducers
});
const rootReducer = (state, action) => {
if (action.type === RESET_REDUX_STATE) {
// clear everything but keep the stuff we want to be preserved ..
delete state.something;
delete state.anotherThing;
}
return combinedReducer(state, action);
}
export default rootReducer;
From a security perspective, the safest thing to do when logging a user out is to reset all persistent state (e.x. cookies, localStorage, IndexedDB, Web SQL, etc) and do a hard refresh of the page using window.location.reload(). It's possible a sloppy developer accidentally or intentionally stored some sensitive data on window, in the DOM, etc. Blowing away all persistent state and refreshing the browser is the only way to guarantee no information from the previous user is leaked to the next user.
(当然,作为共享计算机上的用户,你应该使用“私人浏览”模式,自己关闭浏览器窗口,使用“清除浏览数据”功能,等等,但作为开发人员,我们不能期望每个人都总是那么勤奋)
使用Redux Toolkit的方法:
export const createRootReducer = (history: History) => {
const rootReducerFn = combineReducers({
auth: authReducer,
users: usersReducer,
...allOtherReducers,
router: connectRouter(history),
});
return (state: Parameters<typeof rootReducerFn>[0], action: Parameters<typeof rootReducerFn>[1]) =>
rootReducerFn(action.type === appActions.reset.type ? undefined : state, action);
};