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

如何在Immer的Produce中递归修改值?遇对象不可扩展错误

在Immer的produce函数中递归修改值的最佳实现方案

问题背景

需要在Immer的produce函数中通过递归调用修改嵌套的消息结构,当前实现触发以下错误:

modal.component.tsx:65 未捕获的类型错误:无法添加属性0,对象不可扩展,位于Array.push ()

类型定义:

type WhatsappState = {
  message: Message,
  messages: Message[],
  nextMessage: Message,
  isAuth: boolean,
  qrCode: string,
  modalIsOpen: boolean
}

type Message = {
  value: string;
  id: number;
  nextMessage: Message[];
  uid: string;
  messageState: 'create' | 'submessage' | 'edit';
}

当前尝试的代码:

const submessage = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
    const state = {...WhatsappState, teste: [new Message()]}
    console.table({message: state.message, nextMessage: state.nextMessage})
    console.log(state)
    const newMessage = produce(state, draft => {
      const addMessage = (messages: Array<Message>, uid: string, msg: Message) => {
        for (const message of messages) {
          if (message.uid === uid){
            console.table({message, msg})
            if(!message.nextMessage) message.nextMessage = [];
            message.nextMessage.push(msg)
            return true;
          } else if(addMessage(createDraft(message.nextMessage), uid, msg)){
            return true;
          }
        }
        return false
      }
      addMessage(draft.messages, state.nextMessage.uid, state.message)
    })
    console.log(newMessage);
    WhatsappDispatch({
      type: "set_state",
      payload: { value: newMessage }
    })
    closeModal()
  }

问题分析

  1. 手动调用createDraft属于冗余操作:Immer会自动将draft的嵌套对象转为可修改的代理,无需手动创建draft
  2. 传入的msg是原始状态中的冻结对象:Redux等状态管理库的状态通常不可扩展,直接push会触发“对象不可扩展”错误
  3. 不必要的state复制:produce会基于传入的原始状态创建draft,无需手动浅拷贝state

修正后的实现

const submessage = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
  const newMessage = produce(WhatsappState, draft => {
    const addMessage = (messages: Array<Message>, targetUid: string, newMsg: Message) => {
      for (const message of messages) {
        if (message.uid === targetUid) {
          // 确保nextMessage数组存在
          if (!message.nextMessage) {
            message.nextMessage = [];
          }
          // 浅拷贝新消息,避免引用冻结的原始对象
          message.nextMessage.push({...newMsg});
          return true;
        } 
        // 仅当nextMessage存在时递归,避免传入undefined
        else if (message.nextMessage && addMessage(message.nextMessage, targetUid, newMsg)) {
          return true;
        }
      }
      return false;
    }

    // 操作draft中的数据,而非原始状态
    addMessage(draft.messages, draft.nextMessage.uid, {...draft.message});
  });

  WhatsappDispatch({
    type: "set_state",
    payload: { value: newMessage }
  });
  closeModal();
};

关键优化点

  • 直接基于原始WhatsappState创建draft,省去手动拷贝步骤
  • 递归时直接传递draft中的message.nextMessage,依赖Immer自动处理代理
  • 对新消息做浅拷贝{...draft.message},确保push的是可扩展的新对象
  • 增加message.nextMessage的存在性检查,避免递归调用时传入undefined

内容的提问来源于stack exchange,提问作者Gilmar Antonio Ribeiro dos San

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 14:25:26