使用Immer的produce更新React复杂state失败及类型兼容问题求助
问题描述
我有一个复杂状态 calculationResults,其类型定义如下:
export interface ICalculationResult { hw: IHwCalculationResult; } export interface IHwCalculationResult { header: IHwCalculationResultHeader; agreements: IAgreementItem[]; } export interface IAgreementItem { agreementRows: IAgreementRow[]; }
需要从calculationResults.hw.agreements中移除指定产品对应的条目,再添加从API获取的新agreements数据。由于对象属性多且记录数超5000,我使用了Immer处理:
const nextState = produce(calculatedResults,(draftstate: any) =>{ if(allsite == "1"){ var indices: any = []; draftstate.hw.agreements.forEach(function(value:any,pos: number){ if(value.boQItem.id == productNo) { indices.push(pos); } }); for(var index = indices.length-1;index>=0;index--) { draftstate.hw.agreements.splice(indices[index],1); } draftstate.hw.agreements.push(...data.hw.agreements); } });
请问是否需要调用setCalculationResults(newState)来更新状态?但调用时出现编译错误,提示newState与calculationResults类型不兼容。
解决方案
1. 必须调用setCalculationResults(nextState)更新状态
Immer的produce函数会返回一个全新的状态对象,React的状态更新必须通过setState类方法或者useState返回的更新函数触发,直接修改原状态不会触发组件重新渲染,所以必须调用setCalculationResults(nextState)来完成状态更新。
2. 类型不兼容问题修复
编译错误的核心原因是你大量使用any类型,导致TypeScript无法正确推断nextState的类型,和原状态calculationResults的类型不匹配,修复步骤如下:
- 给
produce指定泛型类型,明确返回值类型:const nextState = produce<ICalculationResult>(calculatedResults, (draftstate) => { // 内部逻辑保持不变(后续再优化类型) }); - 给
indices指定正确的数值数组类型,避免any:const indices: number[] = []; - 遍历
agreements时,给value指定IAgreementItem类型(注意:你的IAgreementItem定义里没有boQItem属性,需要确认接口是否和实际数据匹配,若漏写要补充完整):draftstate.hw.agreements.forEach((value: IAgreementItem, pos: number) => { if (value.boQItem.id === productNo) { indices.push(pos); } }); - 检查API返回的
data.hw.agreements是否符合IAgreementItem[]类型,若API返回类型有差异,需做类型转换或修正接口定义。
3. 大数据量下的代码优化
处理5000条数据时,用filter代替手动收集索引再splice的方式,代码更简洁高效:
const nextState = produce<ICalculationResult>(calculatedResults, (draftstate) => { if (allsite === "1") { // 过滤掉指定产品的条目 draftstate.hw.agreements = draftstate.hw.agreements.filter(item => item.boQItem.id !== productNo); // 添加新数据 draftstate.hw.agreements.push(...data.hw.agreements); } });
这种方式不需要反向遍历删除,减少代码复杂度,同时避免索引操作可能带来的错误。
内容的提问来源于stack exchange,提问作者Raida Adn
相关产品推荐
相关产品推荐

