Redux Toolkit中extraReducer调用含prepare的reducer未触发问题
Redux Toolkit通知系统:extraReducer中调用showNotification无法触发reducer的问题
问题描述
我用Redux Toolkit构建通知系统,需求是在其他slice的特定action触发时自动调用showNotification。目前的情况:
- 组件中通过
dispatch(showNotification(type, message, duration))调用时,prepare回调和reducer都能正常执行 - 在
handleLogInFailure对应的extraReducercase中直接调用showNotification('error', error),仅触发prepare回调,reducer完全不执行 - 尝试过用
notificationSlice.caseReducers.showNotification直接调用reducer,但需要手动构造完整action对象,要处理100+这类场景的话过于繁琐
当前实现代码
const notificationSlice = createSlice({ name: 'notification', initialState: initialState, reducers: { showNotification: { reducer( state: NotificationState, action: PayloadAction<{ type: NotificationType; message: string; duration?: number }> ) { console.log('showNotification: REDUCE', action) const { type, message, duration } = action.payload; state.notifications.push(buildNotification(type, message, duration)); }, prepare(type: NotificationType, message: string, duration?: number) { console.log('showNotification: PREPARE', {type, message, duration}) return { payload: { type, message, duration, }, }; }, }, }, extraReducers: (builder) => { builder.addCase(handleLogInFailure, (state, action: PayloadAction<string>) => { const error = action.payload; console.log('Notifications: handleLogInFailure', action) showNotification('error', error) }); }, });
正确实现方式
方法一:抽离核心逻辑,复用prepare和reducer处理
把通知添加的核心逻辑抽成独立函数,同时复用showNotification的prepare方法处理参数,避免重复代码:
// 抽离通知添加的核心逻辑 const addNotification = (state: NotificationState, payload: { type: NotificationType; message: string; duration?: number }) => { state.notifications.push(buildNotification(payload.type, payload.message, payload.duration)); }; const notificationSlice = createSlice({ name: 'notification', initialState: initialState, reducers: { showNotification: { reducer(state, action: PayloadAction<{ type: NotificationType; message: string; duration?: number }>) { addNotification(state, action.payload); }, prepare(type: NotificationType, message: string, duration?: number) { return { payload: { type, message, duration }, }; }, }, }, extraReducers: (builder) => { builder.addCase(handleLogInFailure, (state, action: PayloadAction<string>) => { const error = action.payload; // 用showNotification的prepare生成标准payload,再调用核心逻辑 const payload = notificationSlice.actions.showNotification.prepare('error', error).payload; addNotification(state, payload); }); }, });
方法二:使用监听中间件(推荐,适合大量场景)
如果需要处理大量类似的跨action触发通知的场景,用Redux Toolkit的createListenerMiddleware更优雅,它可以监听指定action,触发时自动dispatch通知action,完全复用prepare和reducer:
// 创建监听中间件 const listenerMiddleware = createListenerMiddleware(); // 监听handleLogInFailure action,触发时发送错误通知 listenerMiddleware.startListening({ actionCreator: handleLogInFailure, effect: (action, listenerApi) => { const error = action.payload; // 这里dispatch会正常执行prepare和reducer listenerApi.dispatch(notificationSlice.actions.showNotification('error', error)); }, }); // 配置store时加入该中间件 export const store = configureStore({ reducer: { notification: notificationSlice.reducer, // 其他slice的reducer }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().prepend(listenerMiddleware.middleware), });
原写法失效原因
- 直接在
extraReducer中调用showNotification('error', error)只是执行了action creator函数,生成了action对象,但没有将这个action dispatch到store,因此不会触发reducer修改state - 直接调用
caseReducers中的reducer时,需要手动构造完整action对象,跳过了prepare的自动参数处理,所以会增加大量重复代码
内容的提问来源于stack exchange,提问作者JoseAngel ConchelloBueyes
相关产品推荐
相关产品推荐

