如何在Redux reducer合并event对象时实现dates数组的合并去重
实现方案
你当前的reducer用了Immer的draft可变模式,只需调整reduce回调中对event对象的构造逻辑,单独处理dates字段的合并去重即可,完整代码如下:
case LOAD_SUCCESS: draft.loading = false; draft.events = { ...state.events, ...action.events.reduce((acc, newEvent) => { // 取同id的旧事件数据,不存在则默认空对象 const existedEvent = state.events[newEvent.id] || {}; // 合并新旧dates后去重,start和end都一致则视为重复项 const mergedDates = [...(existedEvent.dates || []), ...newEvent.dates].filter( (date, idx, arr) => idx === arr.findIndex(item => item.start === date.start && item.end === date.end) ); // 其他字段用新拉取的版本,仅dates用合并去重后的结果 return { ...acc, [newEvent.id]: { ...newEvent, dates: mergedDates } }; }, {}) }; break;
逻辑说明
- 优先从现有状态中读取同id的旧event数据,避免新增event时报错
- 合并dates数组时对旧数据做兜底处理,无旧数据时默认是空数组
- 去重逻辑通过
findIndex匹配相同start、end的项,仅保留第一个匹配项实现去重 - 构造最终event对象时先展开新拉取的所有字段,再覆盖dates为合并结果,保证除dates外所有字段都是最新的后端值
性能优化(可选)
如果你的event数据量或dates数组长度较大,可以用Map做标记实现O(n)时间复杂度的去重,替换上方的filter去重逻辑即可:
const dateMarker = new Map(); // 先后添加旧、新dates,重复项会自动被后续同key值覆盖 [...(existedEvent.dates || []), ...newEvent.dates].forEach(date => { const uniqueKey = `${date.start}|${date.end}`; dateMarker.set(uniqueKey, date); }); const mergedDates = Array.from(dateMarker.values());
内容的提问来源于stack exchange,提问作者Igor Shmukler
相关产品推荐
相关产品推荐

