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创建了错误的键名。
最优解决步骤
- 确保传入的
part是字符串类型:如果原本传入的是硬件部件对象,调用时取其_name属性作为参数,比如handlePhotoUpload(event, part._name)。 - 修正代码笔误:
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
相关产品推荐
相关产品推荐

