我试图通过更新一个属性 (id) 将数组的一个新元素添加到列表中。我想让它比数组长度多 1。 但是我得到了一些奇怪的输出,添加了每个新对象。所有元素都获得 array.length +1 值。
我使用 let
、const
甚至直接在 this.state.produktsToBuy
上操作对这段代码做了几个变体,每次都得到相同的输出
handleAddToShop = (produktToBuy) => {
const id = this.state.produktsToBuy.length+1;
produktToBuy.id = id + 1;
const produktsToBuy = this.state.produktsToBuy;
produktsToBuy.push(produktToBuy);
this.setState({produktsToBuy});
};
我应该得到输出为 1,2,3,4,5,6,7 但最后我得到 7,7,7,7,7,7
答案 0 :(得分:1)
确保您没有直接改变状态。在 JS 中,对象是一种引用类型。当您将 this.state.produktsToBuy
分配给 const produktsToBuy
并将某些内容推送到 produktsToBuy
时,您实际上是在推送原始 this.state.produktsToBuy
并修改状态。
您可以使用扩展运算符 (...
) 创建状态 (produktsToBuy
) 的浅表副本:
class App extends React.Component {
state = {
items: [
{ name: "test item 1", price: 4.99 },
{ name: "test item 2", price: 7.99 },
{ name: "test item 3", price: 19.99 }
],
produktsToBuy: []
};
handleAddToShop = (produktToBuy) => {
this.setState((prev) => ({
produktsToBuy: [
...prev.produktsToBuy,
{
...produktToBuy,
id: prev.produktsToBuy.length + 1
}
]
}));
};
render() {
return (
<div className="App">
<div style={{ display: "flex" }}>
{this.state.items.map((item) => (
<div
key={item.name}
style={{
border: "1px solid #ccc",
margin: "1rem",
padding: "1rem",
textAlign: "center"
}}
>
<h3>{item.name}</h3>
<p>${item.price}</p>
<button onClick={() => this.handleAddToShop(item)}>Add</button>
</div>
))}
</div>
<pre>{JSON.stringify(this.state.produktsToBuy, null, 2)}</pre>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
答案 1 :(得分:0)
如果除了 produktsToBuy 之外还有其他任何东西,您应该保持之前的所有状态。此外,如果您设置的任何内容都依赖于先前的状态(通常情况下),您总是需要 setState 的功能形式。而且,就像 Zsolt 所说的,你永远不会直接在 React 中改变状态。这是我的答案(与@Zsolt Meszaros 非常相似)。注意:.concat 创建了一个新数组,所以我们不必担心改变原始数组。
handleAddToShop = (produktToBuy) => {
this.setState((prevState) => {
const { produktsToBuy } = prevState;
return {
...prevState,
produktsToBuy: produktsToBuy.concat([
{
...produktToBuy,
id: produktsToBuy.length + 1,
},
]),
};
});
};