You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 21:30:33