You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux Toolkit Slice扩展:如何复用或重写extraReducers?

关于Redux Toolkit Slice扩展的问题

几个月前我就遇到了这个难题,目前正在尝试扩展Redux Toolkit的Slice:已经定义好一个Slice,希望添加或重写部分reducers,现在已经通过自定义extendSlice函数实现了caseReducers的扩展,但无法访问Slice内部的extraReducers,想请教两个问题:

  1. 能否像处理caseReducers那样扩展/重写extraReducers?
  2. extraReducers是否包含在caseReducers中?

附已实现的extendSlice函数代码:

//Extend slice function
/**
 *  @remarks
 * 
 *  This method extends an already declared slice in oreder to attach custom actions to the reducer.
 * 
 *  @param slice The root slice you want to extend
 *  @param caseReducers The case reducers you want to add to the current ones. Current slice reducers won't be override.
 *  @param extraReducers Extra reducers to add to the slice. Don't use this for slices that contain extra reducers! They will be overridden!
 *  
 * 
 *  @returns slice: Slice
 *  The extended slice containing the current reducers concatenated with the new caseReducers and with the extraReducers 
 *
 */

export const extendSlice = ( slice: Slice, caseReducers?: ValidateSliceCaseReducers<any, SliceCaseReducers<any>>, extraReducers?: ( ( builder: ActionReducerMapBuilder<NoInfer<any>> ) => void ) ) => {
  return createSlice( {
    name: slice.name,
    initialState: slice.getInitialState(),
    reducers: { ...caseReducers, ...slice.caseReducers },
    extraReducers
  } );
};

解答

问题2:extraReducers是否包含在caseReducers中?

完全不包含。Redux Toolkit里caseReducers是对应当前Slice自身reducers字段生成的action的处理逻辑,而extraReducers是专门用来处理外部action(比如其他Slice的action、createAsyncThunk生成的异步action等)的,二者是完全独立的结构,在Slice实例中分开存储,你没法从slice.caseReducers里拿到extraReducers的内容。

问题1:能否像处理caseReducers那样扩展/重写extraReducers?

可以实现,但不能直接像合并caseReducers那样操作——因为createSlice执行后,原Slice的extraReducers已经被编译进最终的reducer函数里,并没有保留原始的builder回调或配置对象,需要换两种思路来实现:

方案1:提前抽离原Slice的extraReducers逻辑

如果能控制原Slice的创建流程,建议把原Slice的extraReducers单独写成一个独立函数,这样扩展时可以直接复用并追加新逻辑:

// 抽离原Slice的extraReducers逻辑
const originalExtraReducers = (builder: ActionReducerMapBuilder<MyState>) => {
  builder.addCase(otherSliceAction, (state, action) => {
    // 原extraReducer逻辑
  });
};

// 创建原Slice时传入这个抽离的函数
const originalSlice = createSlice({
  name: 'original',
  initialState: myInitialState,
  reducers: {},
  extraReducers: originalExtraReducers
});

// 修改extendSlice函数,支持合并extraReducers
export const extendSlice = (
  slice: Slice & { extraReducers?: (builder: ActionReducerMapBuilder<any>) => void },
  caseReducers?: ValidateSliceCaseReducers<any, SliceCaseReducers<any>>,
  extraReducers?: (builder: ActionReducerMapBuilder<NoInfer<any>>) => void
) => {
  return createSlice({
    name: slice.name,
    initialState: slice.getInitialState(),
    // 注意顺序:新的caseReducers放后面可以覆盖原有的同名reducer
    reducers: { ...slice.caseReducers, ...caseReducers },
    extraReducers: (builder) => {
      // 先执行原Slice的extraReducers逻辑
      slice.extraReducers?.(builder);
      // 再执行新的extraReducers逻辑
      extraReducers?.(builder);
    }
  });
};

// 使用示例:扩展时追加新的extraReducer
const extendedSlice = extendSlice(originalSlice, newCaseReducers, (builder) => {
  builder.addCase(newExternalAction, (state, action) => {
    // 新增的extraReducer逻辑
  });
});

方案2:合并原reducer与新extraReducer逻辑

如果没法提前抽离原Slice的extraReducers,也可以直接把原Slice的reducer和新的extraReducer逻辑合并:

import { createReducer, AnyAction } from '@reduxjs/toolkit';

export const extendSlice = (
  slice: Slice,
  caseReducers?: ValidateSliceCaseReducers<any, SliceCaseReducers<any>>,
  extraReducers?: (builder: ActionReducerMapBuilder<NoInfer<any>>) => void
) => {
  // 创建包含新caseReducers的基础slice
  const baseSlice = createSlice({
    name: slice.name,
    initialState: slice.getInitialState(),
    reducers: { ...slice.caseReducers, ...caseReducers }
  });

  // 生成新extraReducer对应的reducer函数
  const newExtraReducer = extraReducers 
    ? createReducer(slice.getInitialState(), extraReducers) 
    : (state) => state;

  // 合并原reducer和新extraReducer:先执行原逻辑,再执行新逻辑(新逻辑会覆盖同action的原处理)
  const combinedReducer = (state: any, action: AnyAction) => {
    const updatedState = slice.reducer(state, action);
    return newExtraReducer(updatedState, action);
  };

  // 返回替换了reducer的Slice对象
  return {
    ...baseSlice,
    reducer: combinedReducer
  };
};

这种方式下,如果新的extraReducer和原Slice的extraReducer处理同一个action,新的逻辑会覆盖原有的,因为它是后执行的。

内容的提问来源于stack exchange,提问作者Andy95

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 20:24:57