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

forEach构造新对象时部分seller属性变为React元素问题

问题表现
  • 从Moralis查询返回的原始对象数组中,attributes.seller字段均为字符串类型,遍历过程中直接打印该字段,输出结果全部为正常字符串
  • 遍历提取字段构造新的offer对象推入createdArr数组后,绝大多数offer的seller字段值异常,变为React按钮元素对象,结构为{$$typeof: Symbol(react.element), type: 'button', key: null, ref: null, props: {…}, …},仅少部分对象保留正确字符串值
  • 该逻辑此前运行正常,当前仅部分条目出现异常

相关代码片段

遍历逻辑:

createdResults.forEach((item) => {
  console.log(item.attributes.seller);
  const offer = {
    itemId: Number(item.attributes.itemId),
    token: item.attributes.token,
    amount: item.attributes.amount,
    price: item.attributes.price,
    seller: item.attributes.seller,
  };
  createdArr.push(offer);
})

完整查询逻辑:

const getEvents = async () => {
  let createdArr = [];
  
  const created = new Moralis.Query("SaleCreateddd");
  const createdResults = await created.find();
  
  createdResults.map((item) => {
    // 此处打印item.attributes.seller全部显示为正常字符串
    console.log(item.attributes.seller);
    const offer = {
      itemId: Number(item.attributes.itemId),
      token: item.attributes.token,
      amount: item.attributes.amount,
      price: item.attributes.price,
      seller: item.attributes.seller,
    };
    // 遍历完成后查看createdArr,内部offer的seller字段出现异常
    createdArr.push(offer);
  })
}
问题原因
  1. 浏览器控制台对原始类型(字符串、数字)的打印是瞬时值快照,对引用类型(对象、数组)的打印是懒求值——你在遍历阶段打印item.attributes.seller(字符串,原始类型)正常,只能证明打印瞬间该字段是字符串,无法证明后续逻辑没有修改这个值;等你后续查看createdArr数组时,看到的是对象被修改后的最新值。
  2. Moralis返回的查询结果是封装后的代理对象,不是普通plain object,直接赋值item.attributes.seller没有完全切断和原代理对象的引用关联,后续对原对象的修改会同步影响到你赋值的字段。
  3. 90%的异常来源是后续渲染逻辑的误操作:你在渲染列表/表格时,直接遍历createdArr给项的seller属性赋值了React按钮元素(比如写了类似item.seller = <button>查看卖家</button>的代码),直接覆盖了原始字符串值,没有单独维护渲染相关的属性。
  4. 遍历写法不规范:同时使用map和手动push,map本身会返回新数组,这种混用写法容易埋下引用混乱的隐患。
修复方案
  1. 构造offer对象时,对所有原始值字段做显式类型转换,彻底切断和Moralis代理对象的引用关联,不要直接赋值代理对象的属性引用。
  2. 严格分离原始数据和渲染数据:原始数据数组只存接口返回的业务值,渲染需要的React节点单独存到新的渲染数组/渲染配置字段中,绝对不要直接修改原始数据数组的属性。
  3. 修正遍历写法,统一用map直接返回构造好的新数组,去掉冗余的手动push逻辑。

修复后的代码参考:

const getEvents = async () => {
  const created = new Moralis.Query("SaleCreateddd");
  const createdResults = await created.find();
  
  // 直接通过map返回构造好的新数组,无需额外声明数组手动push
  const createdArr = createdResults.map((item) => {
    // 所有字段显式转成对应的原始类型,彻底切断代理引用
    return {
      itemId: Number(item.attributes.itemId),
      token: String(item.attributes.token),
      amount: Number(item.attributes.amount),
      price: Number(item.attributes.price),
      seller: String(item.attributes.seller), // 强制转成原始字符串,避免后续引用联动
    };
  });

  // 若需要渲染带按钮的列表,单独生成渲染用数组,禁止修改createdArr原始数据
  const renderData = createdArr.map(offer => ({
    ...offer,
    // 渲染用的按钮节点单独存字段,不要覆盖原始seller属性
    sellerAction: <button>{offer.seller}</button>
  }))

  return createdArr;
}

内容的提问来源于stack exchange,提问作者Mandingo San

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 07:42:28