使用 @reduxjs/toolkit 中的 configureStore 时如何重置 Redux Store 的状态?
Posted
技术标签:
【中文标题】使用 @reduxjs/toolkit 中的 configureStore 时如何重置 Redux Store 的状态?【英文标题】:How to reset state of Redux Store when using configureStore from @reduxjs/toolkit? 【发布时间】:2020-03-22 11:25:29 【问题描述】:我看到了注销后清除/重置存储的解决方案,但不明白如何为以下设置 redux 存储的方式实现相同的功能。
Store.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
这里是所有 reducer 如何使用来自 @reduxjs/toolkit 的 createAction 和 createReducer 实现的。
snackbar.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
,
)
【问题讨论】:
你派发一个 thunk 动作,该动作派发一个 reset() 动作到每个 reducer,触发它们返回初始状态。 嗨@timotgl,非常感谢您的回复。你能分享一个例子sn-p吗?那真的很有帮助。 见下方答案 【参考方案1】:根据Dan Abramov's answer,创建一个root reducer,它将简单地将action 委托给您的main 或组合reducer。每当这个根 reducer 收到 reset 类型的操作时,它都会重置状态。
示例:
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's configureStore 配置您的商店,它可能如下所示:
import configureStore from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
export default configureStore(
reducer:
counter: counterReducer,
// ... more reducers
,
);
其中configureStore
的第一个参数reducer
接受一个函数(被视为根减速器)或slice
减速器的对象,它在内部使用 combineReducers 转换为 root reducer。
所以,现在我们可以自己创建并传递根 reducer,而不是传递 slice reducer 的对象(如上所示),我们可以这样做:
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
【讨论】:
这个答案应该在 redux-toolkit 的文档中,谢谢! P.S:看看 CodeSandbox 的实现,Ajeet 在那里添加了更多的 cmets。 有类型的 CodeSandbox 的 TypeScript 版本的机会吗? @Jamie 我的答案中的沙箱链接是 Typescript 版本。你在看什么类型的?或者你的问题到底是什么?如果您有其他问题,请随时提出新问题,您可以在此处发表评论中的链接。 我分叉了你的沙箱并添加了类型-你可以查看here,你也可以在下面看到我的答案。【参考方案2】:我想扩展 Ajeet 的答案,以便那些希望在整个 Redux 存储中实现完全类型安全的人可以访问它。
主要区别在于您需要声明RootState
类型,该类型记录在in the RTK docs
const combinedReducer = combineReducers(
counter: counterReducer
);
export type RootState = ReturnType<typeof combinedReducer>;
然后在执行 logout
函数的 rootReducer 中,您希望通过将 state
参数赋予 RootState
类型和 action
参数 AnyAction
来一直保持类型安全.
难题的最后一部分是将您的状态设置为RootState
类型的空对象,而不是undefined
。
const rootReducer: Reducer = (state: RootState, action: AnyAction) =>
if (action.type === "counter/logout")
state = as RootState;
return combinedReducer(state, action);
;
我在CodeSandbox上fork了Ajeet的答案,添加了需要的类型,大家可以查看here。
【讨论】:
【参考方案3】:带有两个 reducer 的简化示例:
// 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.
;
【讨论】:
【参考方案4】:如果您希望将每个切片重置为其初始状态(与将整个状态设置为空对象不同),您可以使用 extraReducers 响应 logout
操作并返回初始状态。
在 auth.tsx 中:
const logout = createAction('auth/logout')
在 foo.tsx 中:
const initialState =
bar: false,
const fooSlice = createSlice(
name: 'foo',
initialState,
reducers: ,
extraReducers: (builder) =>
builder.addCase(logout, () =>
return initialState
)
,
)
【讨论】:
这是我的首选方法以上是关于使用 @reduxjs/toolkit 中的 configureStore 时如何重置 Redux Store 的状态?的主要内容,如果未能解决你的问题,请参考以下文章
createAsyncThunk 和使用 redux-toolkit 编写 reducer 登录
Redux Toolkit RTK Query 发送查询参数