使用 @reduxjs/toolkit 中的 configureStore 时如何重置 Redux Store 的状态?

IT技术 reactjs redux react-redux redux-toolkit
2021-04-05 14:52:37

我已经看到了注销后清除/重置商店的解决方案,但不明白如何为以下设置 redux 商店的方式实现相同的功能。

商店.js:


import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
import authReducer from './ducks/authentication'
import snackbar from './ducks/snackbar'
import sidebar from './ducks/sidebar'
import global from './ducks/global'
import quickView from './ducks/quickView'
import profileView from './ducks/profileView'

const store = configureStore({
  reducer: {
    auth: authReducer,
    snackbar,
    sidebar,
    global,
    quickView,
    profileView,
  },
  middleware: [...getDefaultMiddleware()],
})

export default store



以下是使用@reduxjs/toolkit 中的 createAction 和 createReducer 实现所有减速器的方式。

小吃店.js:


import { createAction, createReducer } from '@reduxjs/toolkit'

export const handleSnackbar = createAction('snackbar/handleSnackbar')

export const openSnackBar = (
  verticalPosition,
  horizontalPosition,
  message,
  messageType,
  autoHideDuration = 10000
) => {
  return async dispatch => {
    dispatch(
      handleSnackbar({
        verticalPosition,
        horizontalPosition,
        message,
        autoHideDuration,
        messageType,
        isOpen: true,
      })
    )
  }
}

export const closeSnackbar = () => {
  return dispatch => {
    dispatch(handleSnackbar({ isOpen: false }))
  }
}

const initialState = {
  verticalPosition: 'bottom',
  horizontalPosition: 'center',
  message: '',
  autoHideDuration: 6000,
  isOpen: false,
  messageType: 'success',
}

export default createReducer(initialState, {
  [handleSnackbar]: (state, action) => {
    const {
      isOpen,
      verticalPosition,
      horizontalPosition,
      message,
      autoHideDuration,
      messageType,
    } = action.payload
    state.isOpen = isOpen
    state.verticalPosition = verticalPosition
    state.horizontalPosition = horizontalPosition
    state.message = message
    state.autoHideDuration = autoHideDuration
    state.messageType = messageType
  },
})



4个回答

根据丹·阿布拉莫夫的回答,创建一个根减速器,它将简单地将操作委托给您的主减速器或组合减速器每当这个 root reducer 收到一个重置类型的动作时,它就会重置状态。

例子:

const combinedReducer = combineReducers({
  first: firstReducer,
  second: secondReducer,
  // ... all your app's reducers
})

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

因此,如果您已使用@reduxjs/toolkit 的 configureStore配置您的商店,它可能如下所示:

import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';

export default configureStore({
  reducer: {
    counter: counterReducer,
    // ... more reducers
  },
});

whereconfigureStore的第一个参数reducer接受一个函数(被视为根减速器)或减速器的对象slice使用combineReducers在内部转换为根减速器

所以,现在我们可以自己创建并传递根减速器,而不是传递切片减速器的对象(如上所示),这是我们如何做到的:

const combinedReducer = combineReducers({
  counter: counterReducer,
  // ... more reducers
});

现在,让我们创建一个根减速器,在需要时执行我们的重置工作:

const rootReducer = (state, action) => {
  if (action.type === 'counter/logout') { // check for action type 
    state = undefined;
  }
  return combinedReducer(state, action);
};

export default configureStore({
  reducer: rootReducer,
  middleware: [...getDefaultMiddleware()]
});

这是CodeSandbox

有没有可能使用 TypeScript 版本的 CodeSandbox 类型?
2021-05-25 14:52:37
@Jamie 我回答中的沙箱链接是 Typescript 版本。你在看什么类型?或者你的问题究竟是什么?如果您有其他问题,请随时提出新问题,您可以在此处发表评论中的链接。
2021-06-01 14:52:37
这个答案应该在 redux-toolkit 的文档中,谢谢!PS:看一下 CodeSandbox 的实现,Ajeet 在那里添加了更多注释。
2021-06-06 14:52:37
我分叉了你的沙箱并添加了类型 - 你可以在这里查看,你也可以在下面看到我的答案。
2021-06-11 14:52:37

我想扩展 Ajeet 的答案,以便那些希望在整个 Redux 商店中获得完整类型安全的人可以访问它。

主要区别在于您需要声明一个RootState类型,该类型记录在 RTK 文档中

const combinedReducer = combineReducers({
  counter: counterReducer
});

export type RootState = ReturnType<typeof combinedReducer>;

然后在执行logout函数的rootReducer 中,您希望通过为stateparam 提供RootState类型和actionparam来一直保持类型安全AnyAction

难题的最后一部分是将您的状态设置为类型为空的对象RootState而不是undefined.

const rootReducer: Reducer = (state: RootState, action: AnyAction) => {
  if (action.type === "counter/logout") {
    state = {} as RootState;
  }
  return combinedReducer(state, action);
};

我在 CodeSandbox 上分叉了 Ajeet 的答案,添加了所需的类型,您可以在这里查看

带有两个减速器的简化示例:

// actions and reducer for state.first
const resetFirst = () => ({ type: 'FIRST/RESET' });

const firstReducer = (state = initialState, action) => {
    switch (action.type) {
        // other action types here

        case 'FIRST/RESET':
            return initialState;

        default:
            return state;
    }
};


// actions and reducer for state.second
const resetSecond = () => ({ type: 'SECOND/RESET' });

const secondReducer = (state = initialState, action) => {
    switch (action.type) {
        // other action types here

        case 'SECOND/RESET':
            return initialState;

        default:
            return state;
    }
};


const rootReducer = combineReducers({
    first: firstReducer,
    second: secondReducer
});

// thunk action to do global logout
const logout = () => (dispatch) => {
    // do other logout stuff here, for example logging out user with backend, etc..

    dispatch(resetFirst());
    dispatch(resetSecond());
    // Let every one of your reducers reset here.
};

如果您希望将每个切片重置为其初始状态(与将整个状态设置为空对象不同),您可以使用extraReducers来响应logout操作并返回初始状态。

在 auth.tsx 中:

const logout = createAction('auth/logout')

在脚.tsx:

const initialState = {
  bar: false,
}

const fooSlice = createSlice({
  name: 'foo',
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder.addCase(logout, () => {
      return initialState
    })
  },
})
这对我来说是首选方法
2021-06-20 14:52:37