React useState 改变了我不变的初始状态
React useState changes my constant initial state
我的 selectItem
事件改变了我的 initialState
,我故意将其保持不变。
Panel.js
import React, { useState } from "react";
import "./Panel.css";
import Item from "./Item";
const initialState = [
{ text: 1, isSelected: false },
{ text: 2, isSelected: false },
{ text: 3, isSelected: false },
{ text: 4, isSelected: false },
{ text: 5, isSelected: false }
];
export default function Panel() {
const [items, setItems] = useState(initialState);
const selectItem = k => {
console.log(k);
const updatedItems = [...initialState];
updatedItems.find(item => item.text === k).isSelected = true;
setItems(updatedItems);
};
return (
<div className="Panel">
{items.map(item => (
<Item
key={item.text}
text={item.text}
isSelected={item.isSelected}
clicked={selectItem}
/>
))}
</div>
);
}
Item.js
import React from "react";
import "./Item.css";
export default function Item({ text, isSelected, clicked }) {
return (
<div className="Item" onClick={() => clicked(text)}>
{isSelected ? <div style={{ backgroundColor: "red" }}>{text}</div> : text}
</div>
);
}
这样看,你的数组是一个对象数组,每个索引(项)都是对某个特定对象的引用。
基本上,当您创建 updatedItems
数组时,您会将其所有引用分散到一个新的“引用对象的数组”中。因此,从技术上讲,您使用的是完全相同的对象。一旦你 select 一个并改变它,你正在改变 initialState
和 items
都引用的对象。
您正在做的是数组的浅克隆(副本)。
如果你想做一个深度克隆,一个简单的方法是:JSON.parse(JSON.stringify(initialState))
.
您还可以使用 lodash/cloneDeep https://lodash.com/docs/4.17.15#cloneDeep
等实用程序
不过请记住,深度克隆也可能非常昂贵,而且并不总能得到想要的结果。
更改显示为 ...
的行
const updatedItems = [...initialState];
到...
const updatedItems = [...items];
initialState
const 应该只用于初始化 items
状态值。
我的 selectItem
事件改变了我的 initialState
,我故意将其保持不变。
Panel.js
import React, { useState } from "react";
import "./Panel.css";
import Item from "./Item";
const initialState = [
{ text: 1, isSelected: false },
{ text: 2, isSelected: false },
{ text: 3, isSelected: false },
{ text: 4, isSelected: false },
{ text: 5, isSelected: false }
];
export default function Panel() {
const [items, setItems] = useState(initialState);
const selectItem = k => {
console.log(k);
const updatedItems = [...initialState];
updatedItems.find(item => item.text === k).isSelected = true;
setItems(updatedItems);
};
return (
<div className="Panel">
{items.map(item => (
<Item
key={item.text}
text={item.text}
isSelected={item.isSelected}
clicked={selectItem}
/>
))}
</div>
);
}
Item.js
import React from "react";
import "./Item.css";
export default function Item({ text, isSelected, clicked }) {
return (
<div className="Item" onClick={() => clicked(text)}>
{isSelected ? <div style={{ backgroundColor: "red" }}>{text}</div> : text}
</div>
);
}
这样看,你的数组是一个对象数组,每个索引(项)都是对某个特定对象的引用。
基本上,当您创建 updatedItems
数组时,您会将其所有引用分散到一个新的“引用对象的数组”中。因此,从技术上讲,您使用的是完全相同的对象。一旦你 select 一个并改变它,你正在改变 initialState
和 items
都引用的对象。
您正在做的是数组的浅克隆(副本)。
如果你想做一个深度克隆,一个简单的方法是:JSON.parse(JSON.stringify(initialState))
.
您还可以使用 lodash/cloneDeep https://lodash.com/docs/4.17.15#cloneDeep
等实用程序不过请记住,深度克隆也可能非常昂贵,而且并不总能得到想要的结果。
更改显示为 ...
的行const updatedItems = [...initialState];
到...
const updatedItems = [...items];
initialState
const 应该只用于初始化 items
状态值。