我有一个React组件,它在首次加载时会检索数据。
const [data, setDate] = useState(null);
const [originalData, setOriginalData] = useState(null);
useEffect(() => {
async function fn() {
let res = await getObject();
setData({...res});
setOriginalData({...res});
}
fn();
}, [])
我调用2个不同的挂钩来设置data
和originalData
状态。
这样做的目的是使我拥有可以用于组件中某些逻辑的不变版本的数据。
但是,当我更改为data
状态时,似乎也正在更改originalData
状态,而无需我进行任何调用。
const change() => {
let updatedData = {...data};
updatedData.someProperty = 'newValue';
setData(updatedData);
}
我本来希望数据现在包含值为someProperty
的属性newValue
,并且originalData
在初始加载后将保持不变。
但是当我比较它们时,data
和originalData
现在都具有someProperty
。
有人能指出我正确的方向吗?
编辑:添加点差运算符
更改data
更改originalData
的原因不是因为React钩子,而是因为对象在JavaScript中的行为方式。尽管data
和originalData
不同,但它们仍指的是同一对象(来自res
)。 因此,对其中任何一个所做的任何更改都会反映在另一个上,因为它们具有相同的引用。
因此,您应该克隆数据,而不是直接分配它们。
// JSON
const originalData = JSON.parse(JSON.stringify(res))
// Object.assign
const originalData = Object.assign({}, res)
// Or spread opr
const originalData = { ...res }
// Then set the state
setOriginalData(originalData);
ES6方法,如Object.assign和spread运算符会进行浅表复制。如果您需要深层副本,并且您的数据中没有日期,函数,未定义,Infinity,RegExps,地图,集合,Blob,FileList,ImageData,稀疏数组,类型数组或其他复杂类型,请使用JSON解析,字符串化。
查看此question了解有关在JavaScript中进行克隆的更多详细信息