
本文介绍在 react 中深拷贝嵌套对象的实用方法,重点解决表单输入清空时需回退到初始值的场景,涵盖 `json.parse(json.stringify())`、结构化克隆 api 及自定义工具函数等方案,并强调不可变更新与性能注意事项。
在 react 应用中,直接修改 state 对象(如 stateObj.option.c = newValue)会破坏不可变性原则,导致渲染异常或副作用难以追踪。尤其当需要在用户清空输入框时「恢复原始值」时,必须确保初始嵌套对象被完全独立克隆,而非仅复制引用。
✅ 推荐方案:使用 useRef + 深拷贝初始化
以下是一个完整、可运行的示例:
import React, { useState, useEffect, useRef } from 'react'; function FormComponent({ onChange }) { const [stateObj, setStateObj] = useState({ a: "one", b: 2, option: { c: "value", d: { nested: true } } }); // 使用 useRef 安全保存初始 option 的深拷贝(仅在挂载时执行一次) const originalOption = useRef(null); useEffect(() => { // ✅ 安全深拷贝:支持多层嵌套(但不支持函数、Date、RegExp、undefined、Symbol 等) originalOption.current = JSON.parse(JSON.stringify(stateObj.option)); }, []); const handleInputChange = (path, value) => { if (value === '') { // 清空时还原整个 option 对象(非仅 c 字段,确保一致性) setStateObj(prev => ({ ...prev, option: { ...originalOption.current } // 再次浅拷贝以确保新引用 })); onChange?.(path, originalOption.current.c); } else { // 更新指定路径(简化版:仅支持两级如 ["option", "c"]) setStateObj(prev => { const newState = { ...prev }; const [parentKey, childKey] = path; if (newState[parentKey] && typeof newState[parentKey] === 'object') { newState[parentKey] = { ...newState[parentKey], [childKey]: value }; } return newState; }); onChange?.(path, value); } }; return ( handleInputChange(['option', 'c'], e.target.value)} onBlur={(e) => { if (e.target.value === '') { handleInputChange(['option', 'c'], ''); } }} placeholder="编辑后留空可恢复初始值" /> ); } export default FormComponent;
⚠️ 注意事项与替代方案
| 方法 | 适用场景 | 局限性 | 推荐指数 |
|---|---|---|---|
| jsON.parse(json.stringify(obj)) | 快速原型、纯数据对象(无函数/date/循环引用) | ❌ 不支持 undefined、function、Date、regexp、map、Set、BigInt、symbol;会丢失原型链 | ⭐⭐⭐⭐ |
| structuredClone()(现代浏览器) | 需要完整类型保真(chrome 98+ / firefox 94+) | ❌ IE 不支持,node.js | ⭐⭐⭐⭐⭐ |
| Lodash _.cloneDeep() | 企业级项目,需稳定兼容性 | ⚠️ 增加包体积(约 7KB gzip) | ⭐⭐⭐⭐ |
| 自定义递归克隆函数 | 极简依赖要求,可控性强 | ⚠️ 易遗漏边界情况(如循环引用、特殊对象) | ⭐⭐⭐ |
? 关键提醒: useRef 本身不触发重渲染,适合存储持久不变的初始快照; 即使 originalOption.current 是深拷贝,setStateObj 中仍需用 { …originalOption.current } 浅拷贝,确保 React 检测到引用变化; 若 state 结构复杂(如含数组、深层嵌套),建议封装通用 setIn / getIn 工具函数,或采用 Immer 简化不可变更新逻辑。
✅ 总结
克隆 React state 中的嵌套对象,核心在于深拷贝 + 引用隔离。对于大多数表单场景,useRef + JSON.parse(JSON.stringify()) 组合简洁可靠;对高保真需求,优先选用 structuredClone();长期维护项目可引入 Immer 实现“直觉式”不可变更新。始终牢记:永远不要直接修改 state 对象,所有更新都应返回新引用。