Reducer中多Action实现相同状态转换的最佳实践方案
嘿,这个场景太常见了!既要遵循Mike Ryan提到的「每个事件对应唯一Action」的最佳实践,又不想在Reducer里写重复的状态更新代码,其实有两种很干净的实现方式:
方法1:提取重复逻辑为纯函数
把两个Action共享的状态更新逻辑抽成一个独立的纯函数,然后在两个on回调里复用它。这样既保留了每个Action的独立性,又消除了代码重复。
首先定义复用的逻辑函数:
// 提取状态更新逻辑到纯函数 const updateSelectedRawSignal = (state: RawSignalsState, signal: RawSignal) => { return { ...state, selectedRawSignal: entitiesSelectors.selectEntities(state)[signal.id] }; };
然后在Reducer里调用这个函数:
on(rawSignalsActions.rawSignalEditInplace, (state, { signal }) => updateSelectedRawSignal(state, signal)), on(rawSignalsActions.rawSignalEdit, (state, { signal }) => updateSelectedRawSignal(state, signal)),
这种方式的好处是,如果后续这个状态更新逻辑需要修改,或者要在其他地方复用,只需要改这一个函数就好,非常维护友好。
方法2:让Reducer同时监听多个Action
Redux Toolkit的on方法支持传入一个Action数组,让同一个回调响应多个不同的Action。这是更简洁的写法,适合逻辑简单的场景:
on( // 同时监听两个独立的Action [rawSignalsActions.rawSignalEditInplace, rawSignalsActions.rawSignalEdit], (state, { signal }) => { return { ...state, selectedRawSignal: entitiesSelectors.selectEntities(state)[signal.id] }; } ),
这种方式直接告诉Reducer:「这两个不同的Action,触发相同的状态更新」——但每个Action依然是各自对应不同的事件,完全没有违反「不为不同事件调用同一个公共Action」的最佳实践,因为我们没有让多个事件去触发同一个Action,只是让Reducer对它们做出相同的响应。
为什么这两种方式都符合最佳实践?
Mike Ryan的核心建议是不要让不同的业务事件复用同一个Action,因为这会让Action的语义模糊,难以追踪事件来源。而我们的两种方案都保留了rawSignalEditInplace和rawSignalEdit的独立性,它们依然各自对应不同的操作场景(比如一个是原地编辑触发,一个是常规编辑触发),只是它们带来的状态变化是一样的——这完全是合理的,不同的事件导致相同的状态更新是很常见的场景。
内容的提问来源于stack exchange,提问作者DevLoverUmar

