如何解决在功能组件中更新状态时进行浅拷贝有什么风险或副作用?
我有下面的小例子,我假设如果我在替换状态之前做一个浅拷贝,我的会话属性不会是新的,而只是对旧的引用。我已经将浅拷贝定义为变量 newSpeakersDataShallow
和名为 newSpeakersDataDeep
的深拷贝变量。
如果您更改传递给 setSpeakerData
的内容,您会看到它们的工作方式相同。我的问题是,我的风险是什么?如果我知道我不会更改会话数组,是否可以使用浅拷贝?
(这只是一个简化的例子,所以答案不是,不妨使用 deep,因为在这种情况下很容易做到)。
https://codesandbox.io/s/clever-varahamihira-ry9x4?file=/pages/index.js:0-1990
与代码沙盒相同的代码:
import { useEffect,useState } from "react";
const data = [
{
id: "1",first: "Joe",last: "Smith",favorite: true,sessions: [
{
id: "32",title: "Rails powered by",},{
id: "58",title: "Hello World to .NET 3.5 interoperable Web service",],{
id: "2",first: "Jon",last: "Jones",favorite: false,sessions: [
{
id: "1011",title: "scalability and deployability",{
id: "3",first: "Sam",last: "Hulk",sessions: [],];
function Speakers() {
const [speakersData,setSpeakersData] = useState([]);
useEffect(() => {
setSpeakersData(data);
},[]);
return (
<>
{speakersData.map(function (speaker) {
return (
<div key={speaker.id}>
<button
onClick={() => {
const newSpeakersDataShallow = speakersData.map(function (rec) {
return speaker.id == rec.id
? { ...rec,favorite: !rec.favorite }
: { ...rec };
});
const newSpeakersDataDeep = speakersData.map(function (rec) {
return speaker.id == rec.id
? {
...rec,favorite: !rec.favorite,sessions: [...rec.sessions],}
: { ...rec };
});
// RESULTS ARE SAME WHETHER DEEP OR SHALLOW COPY USED
setSpeakersData(newSpeakersDataDeep);
}}
>
Toggle Favorite
</button>
{speaker.id} {speaker.first} {speaker.last}{" "}
{JSON.stringify(speaker.sessions)}{" "}
{speaker.favorite === true ? "true" : "false"}
</div>
);
})}
</>
);
}
export default Speakers;
解决方法
如果数据没有被以任何方式操作,那么使用浅拷贝是可以的。
使用浅拷贝的风险仅存在于您正在执行的操作更改数据时,因为这将导致绕过 setState
的反应状态的直接突变,这可能会导致副作用,例如 state not匹配渲染结果。
对于深度克隆,您可以使用像 lodash.cloneDeep 这样的库来避免手动处理对象。
,当以最佳方式更新状态时,您将只为您更新的对象制作新副本,而让其他对象保持不变。保留旧引用不会对您状态的未更改部分产生任何影响,无需复制它们。
您的目标是避免改变状态的各个部分。通过这种方式,您可以确保您的更新状态正确反映而不会出现意外行为。没有必要创建深度副本,对于深度嵌套状态来说可能代价高昂。
你的第一个例子接近我的方法:
-
map
创建一个新数组,这样你就不会改变它; - 为需要更改的对象创建一个浅拷贝,并正确更新所需的值;
区别在于未触及的对象不需要返回新副本{...rec}
。鉴于它没有受到影响,您可以安全地返回相同的对象,避免新对象的成本。
const newSpeakersDataShallow = speakersData.map(function (rec) {
return speaker.id == rec.id
? { ...rec,favorite: !rec.favorite }
: rec;
});
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。