使用 @reduxjs/toolkit 的 configureStore 时如何重置 Redux Store 的状态?
How to reset state of Redux Store when using configureStore from @reduxjs/toolkit?
我已经看到 clearing/resetting 注销后商店的解决方案,但不明白如何为以下设置 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
这里是如何使用来自@reduxjs/toolkit.
的 createAction 和 createReducer 实现的所有 reducer
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
},
})
带有两个减速器的简化示例:
// 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.
};
根据 ,创建一个 root reducer,它将简单地将 action 委托给您的 主要或组合减速器。每当这个根 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
reducers which is internally converted to root reducer using combineReducers。
所以,现在我们可以自己创建并传递根 reducer,而不是传递 slice reducer 的对象(如上所示),这是我们可以做到的方法:
const combinedReducer = combineReducers({
counter: counterReducer,
// ... more reducers
});
现在,让我们创建一个 root reducer,它在需要时执行我们的 reset 工作:
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
我想扩展 Ajeet 的答案,以便那些希望在整个 Redux 存储中完全类型安全的人可以访问它。
主要区别在于您需要声明一个 RootState
类型,该类型已记录 in the RTK docs
const combinedReducer = combineReducers({
counter: counterReducer
});
export type RootState = ReturnType<typeof combinedReducer>;
然后在您的 rootReducer 中,您正在执行 logout
函数,您希望通过为 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。
如果您希望将每个切片重置为其初始状态(与将整个状态设置为空对象不同),您可以使用 extraReducers 来响应 logout
操作和 return初始状态。
在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
})
},
})
我已经看到 clearing/resetting 注销后商店的解决方案,但不明白如何为以下设置 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
这里是如何使用来自@reduxjs/toolkit.
的 createAction 和 createReducer 实现的所有 reducersnackbar.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
},
})
带有两个减速器的简化示例:
// 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.
};
根据
示例:
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
reducers which is internally converted to root reducer using combineReducers。
所以,现在我们可以自己创建并传递根 reducer,而不是传递 slice reducer 的对象(如上所示),这是我们可以做到的方法:
const combinedReducer = combineReducers({
counter: counterReducer,
// ... more reducers
});
现在,让我们创建一个 root reducer,它在需要时执行我们的 reset 工作:
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
我想扩展 Ajeet 的答案,以便那些希望在整个 Redux 存储中完全类型安全的人可以访问它。
主要区别在于您需要声明一个 RootState
类型,该类型已记录 in the RTK docs
const combinedReducer = combineReducers({
counter: counterReducer
});
export type RootState = ReturnType<typeof combinedReducer>;
然后在您的 rootReducer 中,您正在执行 logout
函数,您希望通过为 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。
如果您希望将每个切片重置为其初始状态(与将整个状态设置为空对象不同),您可以使用 extraReducers 来响应 logout
操作和 return初始状态。
在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
})
},
})