为什么React中调用dispatch时state值异常导致数据保存失败?
问题根源
你复用的两个dispatch函数原本是为单字段实时自动保存场景设计的,每个函数内部都会从Redux store读取当前的userSettings,仅修改自身对应的字段后提交。当你同时调用两个函数批量保存时,会出现覆盖问题:
- 你控制台打印的
props.userToggleSettings是父组件维护的本地临时状态,两个开关的取值都是正确的,传给两个dispatch函数的参数本身没有问题 - 两个异步
dispatch函数几乎同时执行,各自从store读取的都是未更新的初始userSettings,构造的更新对象仅修改自身对应的字段,另一个字段保留store里的旧值 - 两次请求先后提交后,后完成的请求会把前一个请求修改的字段重新覆盖为旧值,最终导致保存失败
解决方案
推荐采用「批量一次性更新」的方案,避免多次请求冲突:
步骤1:新增批量更新的dispatch方法
在你的userSettings dux文件中新增一个支持多字段同时更新的方法:
export function updateBatchUserSettings(newSettings) { return async (dispatch, getState) => { const { appCustomizations } = getState(); // 合并原有配置和新的修改项 const updatedUserSettings = { ...appCustomizations.userSettings, ...newSettings }; try { await saveAppCustomizationByName( CUSTOMIZATIONS.USER_SETTINGS, updatedUserSettings ); dispatch(setSettings(updatedUserSettings)); } catch (err) { dispatch( bannerDux.alertBanner({ description: "FAILED TO UPDATE USER DATA", }) ); } }; }
步骤2:在mapDispatchToProps中注册新方法
export function mapDispatchToProps(dispatch) { return { // 保留原有方法不影响旧逻辑 toggleCascadingPanels: (hasCascadingPanels) => dispatch(userSettingsDux.toggleCascadingPanels(hasCascadingPanels)), toggleIncludeAttachments: (hasIncludeAttachments) => dispatch(userSettingsDux.toggleIncludeAttachments(hasIncludeAttachments)), // 新增批量更新方法 updateBatchUserSettings: (newSettings) => dispatch(userSettingsDux.updateBatchUserSettings(newSettings)) }; }
步骤3:修改保存逻辑,调用批量更新方法
const saveUserSettings = (props) => { console.log("userSettings ==>\n", props.userToggleSettings); // 一次性提交所有修改,仅发一次请求 props.updateBatchUserSettings({ alwaysIncludeAttachments: props.userToggleSettings.includeAttachments, usesCascadingPanels: props.userToggleSettings.cascadingPanels }); };
如果你不想修改现有dispatch逻辑,也可以采用串行执行的临时方案(不推荐,会发送两次请求,性能更差):
const saveUserSettings = async (props) => { console.log("userSettings ==>\n", props.userToggleSettings); // 等第一个请求完成更新store后,再执行第二个请求 await props.toggleIncludeAttachments(props.userToggleSettings.includeAttachments); await props.toggleCascadingPanels(props.userToggleSettings.cascadingPanels); };
内容的提问来源于stack exchange,提问作者Hussam Ahmed
相关产品推荐
相关产品推荐

