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

Formik嵌套对象更新异常:如何修改嵌套字段而非新建对象

Formik嵌套对象字段更新问题解决

问题场景

在React+Formik应用中,表单包含嵌套对象结构用于表示硬件部件,初始表单值如下:

export const formValues = {
  client: {
    firstName: '',
    lastName: '',
    email: '',
    phoneNumber: '',
  },
  specification: {
    machineMake: '',
    machineModel: '',
    machineSerial: '',
    machinePhoto: null, // Store photo as a File object
    hardwareParts: {
      hdd: {
        _name:"hdd",
        label: 'HDD/SSD',
        serial: '',
        photo: null,
      },
      ram: {
        _name:"ram",
        label: 'RAM',
        serial: '',
        photo: null,
      },
      rom: {
        _name:"rom",
        label: 'ROM',
        serial: '',
        photo: null,
      },
      pin: {
        _name:"pin",
        label: '3-Pin',
        serial: '',
        photo: null,
      },
      adapter: {
        _name:"adapter",
        label: 'Adapter',
        serial: '',
        photo: null,
      },
      battery: {
        _name:"battery",
        label: 'Battery',
        serial: '',
        photo: null,
      },
      // 可按相同结构添加更多硬件部件
    },
    machineCondition: ''
  },
}

尝试通过formik.setFieldValue更新硬件部件的photo字段时,传入路径specification.hardwareParts.${part}.photo,结果并未更新原有对象内的字段,反而生成了一个键为[object Object]的独立对象,而非直接修改对应部件的photo属性。

尝试的代码

const handlePhotoUpload = (event, part) => {
        console.log("part",part)
        const file = event.target.files[0];
         if (file) {
           const reader = new FileReader();
           reader.readAsDataURL(file);
           reader.onloadend = () => {
            const base64Data = reader.result.split(',')[1]; // 提取base64数据
             if (part) {
                console.Consolelog
               formik.setFieldValue(`specification.hardwareParts.${part}.photo`, base64Data); // 更新逻辑
             } else {
               formik.setFieldValue('specification.machinePhoto', base64Data);
             }
          };
         }
      };

预期输出

hdd : {_name: 'hdd', label: 'HDD/SSD', serial: '', photo: '/9j/4f98RXhpZgAASUkqAAgAAAATAAABAwABAAAAoA8AAAEBAw…CAAAAAAABCjYAAAAjAAAAAAChChMAAAATAAAAJAAAAFNFRlQ='} 

当前错误输出

hardwareParts
: {
battery: 
{_name: 'battery', label: 'Battery', serial: '', photo: null},
hdd
: 
{_name: 'hdd', label: 'HDD/SSD', serial: '', photo: null},
[object Object]
: 
{photo: '/9j/4f98RXhpZgAASUkqAAgAAAATAAABAwABAAAAoA8AAAEBAw…CAAAAAAABCjYAAAAjAAAAAAChChMAAAATAAAAJAAAAFNFRlQ='}}

解决方案

问题核心在于part参数的类型错误:你传入的part不是字符串,而是对象,模板字符串specification.hardwareParts.${part}.photo会把对象自动转为[object Object],导致Formik创建了错误的键名。

最优解决步骤

  1. 确保传入的part是字符串类型:如果原本传入的是硬件部件对象,调用时取其_name属性作为参数,比如handlePhotoUpload(event, part._name)。
  2. 修正代码笔误:console.Consolelog改为console.log(避免控制台报错)。

修正后的代码示例:

// 调用示例:
// 直接传入字符串部件名
// <input type="file" onChange={(e) => handlePhotoUpload(e, 'hdd')} />

// 遍历硬件部件对象时传入_name
// Object.values(formik.values.specification.hardwareParts).map(part => (
//   <input key={part._name} type="file" onChange={(e) => handlePhotoUpload(e, part._name)} />
// ))

const handlePhotoUpload = (event, part) => {
  const file = event.target.files[0];
  if (file) {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onloadend = () => {
      const base64Data = reader.result.split(',')[1];
      if (part) {
        // 此时part为字符串,路径解析正确
        formik.setFieldValue(`specification.hardwareParts.${part}.photo`, base64Data);
      } else {
        formik.setFieldValue('specification.machinePhoto', base64Data);
      }
    };
  }
};

备选方案(手动合并对象)

如果无法修改传入的part参数类型,也可以通过formik.setValues手动合并对象来更新:

formik.setValues({
  ...formik.values,
  specification: {
    ...formik.values.specification,
    hardwareParts: {
      ...formik.values.specification.hardwareParts,
      [part._name]: {
        ...part,
        photo: base64Data
      }
    }
  }
});

优先推荐第一种方案,直接确保part为字符串,让Formik的路径解析正常工作,更简洁高效。

内容的提问来源于stack exchange,提问作者Steve Gaita

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 04:36:04