Redux-thunk & redux-promise:PENDING无payload,如何实现本地即时更新?
解决方案
你写的那种自定义字段的写法完全可行,根本不需要单独拆分本地更新的action,根据你用的中间件类型选对应的方案就行:
方案1:使用redux-promise-middleware(即带PENDING/FULFILLED/REJECTED后缀动作的中间件)
这种场景下你提的写法本身就是官方支持的用法,不需要额外修改:
export function updateUser(user) { return { type: UPDATE_USER, payload: { promise: userServices.update(user), // 自定义字段会被中间件原样透传到所有生命周期动作中 localPayload: user, } } }
中间件处理这个动作时,会自动提取payload里的promise字段,剩下的所有自定义字段(比如这里的localPayload)会被同时挂载到最终生成的PENDING/FULFILLED/REJECTED三个动作的顶层,不需要你手动处理。
触发PENDING阶段时生成的动作结构如下,直接就能拿到需要同步的本地数据:
{ type: `${UPDATE_USER}_PENDING`, localPayload: user, // 直接透传的自定义字段 payload: { localPayload: user } // 同时也保留在payload中,可按需取值 }
你只需要在reducer里监听${UPDATE_USER}_PENDING动作,直接读取action.localPayload更新本地状态即可,完全实现即时UI响应。
注:如果你用的是老版本的纯
redux-promise中间件,它只会处理payload直接为promise的场景,不支持这种payload为对象的写法,这种情况选方案2即可。
方案2:纯redux-thunk环境(无额外Promise中间件)
也不需要拆分独立的action创建函数,直接在thunk内部先触发本地更新即可,代码非常简洁:
export function updateUser(user) { return (dispatch) => { // 第一步同步触发本地更新,即时响应用户操作,不需要单独导出这个action dispatch({ type: 'UPDATE_USER_OPTIMISTIC', payload: user, }) // 第二步正常发起服务器请求,后续处理成功/失败逻辑 return userServices.update(user) .then(res => dispatch({ type: 'UPDATE_USER_FULFILLED', payload: res })) .catch(err => dispatch({ type: 'UPDATE_USER_REJECTED', error: err })) } }
这种写法里的本地更新动作只是内部触发的标记,不需要单独封装action创建函数,也不会增加冗余代码,如果后续需要做请求失败的状态回滚,也可以直接在catch逻辑里处理,非常灵活。
补充注意点
这种先更新本地再请求服务器的模式就是标准的乐观更新实践:
- 如果服务器返回的最终数据和本地传入的完全一致,只需要在PENDING阶段更新一次即可,FULFILLED阶段不需要额外处理
- 如果服务器返回的数据存在差异(比如自动补全字段、脱敏处理),可以在FULFILLED阶段用服务器返回的真实数据覆盖本地状态,完全兼容现有逻辑
内容的提问来源于stack exchange,提问作者Augustin Riedinger
相关产品推荐
相关产品推荐

