React.js复制对象数组为state时原引用被修改问题求解
问题原因
你之前使用的两种写法都属于浅拷贝,最多只能拷贝最外层1-2层的结构:
[...USERS_TYPE]仅拷贝了最外层的数组,数组内的用户对象、inputs数组、inputs内的配置对象全部和原USERS_TYPE共享引用USERS_TYPE.map(item=>({...item}))仅额外拷贝了外层的用户对象,内部的inputs数组和数组内的配置对象仍然是原引用
所以修改内层属性时,会直接改动原常量的值。
解决方案
方案1:逐层手动拷贝(性能最优,适合固定结构场景)
State初始化阶段
逐层拷贝所有嵌套的对象和数组:
const [users, setUsers] = useState( USERS_TYPE.map(user => ({ ...user, // 拷贝inputs数组,同时拷贝数组内每个输入配置对象 inputs: user.inputs.map(input => ({...input})) })) )
State修改阶段
不要直接修改原引用的属性,修改时也要逐层返回新对象:
const changes = users.map((user, idx) => { // 非选中项直接返回原对象,不做修改 if (idx !== selected - 1) return user const errIndexList = validation(user.inputs) // 生成新的inputs数组,错误项返回新的配置对象 const newInputs = user.inputs.map((input, inputIdx) => { return errIndexList.includes(inputIdx) ? {...input, error: true} : input }) // 返回新的用户对象 return {...user, inputs: newInputs} }) setUsers(changes)
方案2:原生深拷贝(写法简单,适合嵌套层级复杂的场景)
如果结构嵌套层级多,手动逐层拷贝太麻烦,可以直接用浏览器原生的structuredClone方法做深拷贝,你的场景里都是普通字符串、布尔值、数组、对象,完全兼容:
// 初始化时直接深拷贝原常量 const [users, setUsers] = useState(structuredClone(USERS_TYPE))
注意:
structuredClone不支持拷贝函数、Symbol、循环引用等特殊类型值,普通业务配置场景都可以正常使用。
内容的提问来源于stack exchange,提问作者rick
相关产品推荐
相关产品推荐

