在使用useState做数据操作更新的时候,有一些复杂数据类型,一个对象数组里包含,函数,dom等等复杂数据类型,想要进行数据更新,并且视图更新的情况下,因useState的特性就必须进行深拷贝赋值。
方式
1、JSON.stringify配合JSON.parse 这个有限制,我们的数据类型包含,函数。它会丢失
2、Lodash 里的深拷贝方法
3、递归实现
我这里通过递归直接写的方法,发现拷贝是可以了,但是无法保留之前dom上的视图状态看,查阅文档如下
React Hooks 是 React 的一种新特性,它提供了一种更加方便和简洁的方式来编写组件。React Hooks 中的 state 和 props 都是可变的,当组件的状态或属性发生改变时,React 会重新渲染组件。在进行深拷贝时,只是将组件的 state 或 props 对象中的值复制到了一个新的对象中,新的对象和原来的对象是完全独立的,它们的引用关系已经被断开。而 React 在进行组件渲染时,是根据组件的 state 和 props 来计算出组件的视图状态的,当组件的 state 或 props 发生改变时,React 会重新计算组件的视图状态,并重新渲染组件。
因此,如果在进行深拷贝后,将新的对象作为组件的 state 或 props,那么组件的视图状态就会丢失,因为 React 认为组件的状态或属性并没有发生改变,所以不会重新计算组件的视图状态。要保留组件的视图状态,需要确保深拷贝后的对象和原来的对象具有相同的引用关系,或者使用其他方法来进行状态管理,例如使用 React Context 或 Redux 等状态管理库。
解决
我这里是找了一个npm包来处理了
首先,我们需要安装一个不可变数据结构库,这里我选择使用Immer。您可以使用以下命令进行安装:
> npm install immer
然后,我们可以使用Immer来创建一个新的状态对象,而不必担心丢失与原始状态相关联的视图状态。下面是一个示例:
如图:
![11226018-897e6b3fc8c148a2.png](//static.cnodejs.org/Fr02azpSbkMtMHjEaej_gQahg_Kv)
> import React, { useState } from 'react';
import produce from 'immer';
function MyComponent() {
const [data, setData] = useState({
name: 'John',
age: 30,
address: {
city: 'New York',
country: 'USA'
}
});
const handleButtonClick = () => {
const newData = produce(data, draftData => {
draftData.age = 31;
draftData.address.city = 'Los Angeles';
});
setData(newData);
};
return (
<div>
<p>Name: {data.name}</p>
<p>Age: {data.age}</p>
<p>City: {data.address.city}</p>
<p>Country: {data.address.country}</p>
<button onClick={handleButtonClick}>Update</button>
</div>
);
}
在上面的示例中,我们使用了Immer的produce方法来创建一个新的状态对象newData,并在其中更新了age和address.city属性。然后,我们使用setData方法将新的状态对象设置为组件的状态。由于我们使用了不可变数据结构,与原始状态相关联的视图状态将不会丢失。
请注意,我们在handleButtonClick方法中使用了produce方法来创建新的状态对象。produce方法将原始状态对象data作为第一个参数,并接受一个回调函数作为第二个参数。在回调函数中,我们可以使用类似于修改原始状态对象的方式来修改draftData对象,但实际上我们是在修改新的状态对象。最后,produce方法将返回一个新的状态对象newData,该对象包含所有更改。
有疑问加站长微信联系(非本文作者))