我正在使用Redux进行状态管理。 如何将存储重置为初始状态?

例如,假设我有两个用户帐户(u1和u2)。 想象下面的一系列事件:

用户u1登录到应用程序并做了一些事情,所以我们在存储中缓存一些数据。 用户u1退出。 用户u2无需刷新浏览器即可登录应用。

此时,缓存的数据将与u1关联,我想清理它。

当第一个用户注销时,如何将Redux存储重置为初始状态?


当前回答

我发现Dan Abramov的回答很适合我,但它触发了ESLint no-param-reassign错误- https://eslint.org/docs/rules/no-param-reassign

下面是我如何处理它,确保创建一个状态的副本(这是,在我的理解,Reduxy的事情要做…):

import { combineReducers } from "redux"
import { routerReducer } from "react-router-redux"
import ws from "reducers/ws"
import session from "reducers/session"
import app from "reducers/app"

const appReducer = combineReducers({
    "routing": routerReducer,
    ws,
    session,
    app
})

export default (state, action) => {
    const stateCopy = action.type === "LOGOUT" ? undefined : { ...state }
    return appReducer(stateCopy, action)
}

但是也许创建一个状态的副本,然后把它传递给另一个减速器函数,它会创建一个状态的副本,这有点过于复杂了?这篇文章读起来不太好,但更切题:

export default (state, action) => {
    return appReducer(action.type === "LOGOUT" ? undefined : state, action)
}

其他回答

定义一个动作:

const RESET_ACTION = {
  type: "RESET"
}

然后在每个减速器中假设您使用switch或if-else通过每个减速器处理多个动作。我要拿开关的箱子。

const INITIAL_STATE = {
  loggedIn: true
}

const randomReducer = (state=INITIAL_STATE, action) {
  switch(action.type) {
    case 'SOME_ACTION_TYPE':

       //do something with it

    case "RESET":

      return INITIAL_STATE; //Always return the initial state

   default: 
      return state; 
  }
}

这样当你调用RESET动作时,你的reducer就会用默认状态更新存储。

现在,注销,你可以处理如下:

const logoutHandler = () => {
    store.dispatch(RESET_ACTION)
    // Also the custom logic like for the rest of the logout handler
}

每次用户登录时,不需要刷新浏览器。Store将始终处于默认状态。

store.dispatch(RESET_ACTION)只是详细阐述了这个思想。你很可能会有一个用于此目的的动作创建者。更好的方法是使用LOGOUT_ACTION。

一旦分派了这个LOGOUT_ACTION。然后,一个自定义中间件可以用Redux-Saga或Redux-Thunk拦截这个动作。然而,这两种方法都可以分派另一个动作“RESET”。通过这种方式,存储注销和重置将同步发生,您的存储将为另一个用户登录做好准备。

为了将状态重置为初始状态,我编写了以下代码:

const appReducers = (state, action) =>
   combineReducers({ reducer1, reducer2, user })(
     action.type === "LOGOUT" ? undefined : state,
     action
);

Dan Abramov的答案没有做的一件事是为参数化选择器清除缓存。如果你有一个这样的选择器:

export const selectCounter1 = (state: State) => state.counter1;
export const selectCounter2 = (state: State) => state.counter2;
export const selectTotal = createSelector(
  selectCounter1,
  selectCounter2,
  (counter1, counter2) => counter1 + counter2
);

然后你必须像这样在登出时释放它们:

selectTotal.release();

否则,最后一次调用选择器的记忆值和最后一个参数的值仍将在内存中。

代码示例来自ngrx文档。

我已经创建了一个组件来给Redux重置状态的能力,你只需要使用这个组件来增强你的存储和分派一个特定的动作。类型触发重置。执行的想法和Dan Abramov在他们的回答中说的是一样的。

Github: https://github.com/wwayne/redux-reset

结合Dan Abramov的回答,Ryan Irilli的回答和Rob Moorman的回答,来解释保持路由器状态和初始化状态树中的其他所有东西,我最终得到了这样的答案:

const rootReducer = (state, action) => appReducer(action.type === LOGOUT ? {
    ...appReducer({}, {}),
    router: state && state.router || {}
  } : state, action);