我使用React创建待办事项列表应用程序。我的州有项目,也删除了项目,以便可以恢复:
state = {
items: ['item 1', 'item 2', 'item 3'],
deletedItems: ['item 4', 'item 5']
};
我删除项目的功能因此必须从项目状态中删除该项目并将其置于deletedItems状态。
removeItem(number) {
const itemsState = this.state.items;
const deletedItemsState = this.state.deletedItems;
const itemToBeDeleted = itemsState[number];
deletedItemsState.push(itemToBeDeleted);
itemsState.splice(number, 1);
this.setState({ items: itemsState });
}
上面的代码有效,但我很困惑为什么在没有调用setState的情况下更新了deletedItems状态。我不遵循这里的最佳做法吗?
答案 0 :(得分:3)
我不遵循这里的最佳做法吗?
不。问题是你没有像你可能认为的那样处理临时变量,而是直接改变deletedItems
。基本上是:
const itemsState = this.state.items;
const deletedItemsState = this.state.deletedItems;
这些行不会创建相应状态变量的副本,而只会创建对它们的引用。
所以当你这样做时
deletedItemsState.push(itemToBeDeleted);
你直接改变了状态!这是禁忌,你可能已经知道了。
要理解这一点,您必须了解Primitive和Compound值之间的分配有不同的作用。
例如:
var x = y;
如果x
是字符串,数字,布尔值,空值或未定义,则 y
将复制y
的值。但是,如果它是一个对象,则数组或函数x
将存储其引用。
您需要做的是创建它们的浅表副本。像这样:
const itemsState = this.state.items.slice();
const deletedItemsState = this.state.deletedItems.slice();
这将使itemsState
和deletedItemsState
分别与this.state.item
和this.state.deletedItems
分开。
class MyApp extends React.Component {
constructor() {
super();
this.state = {
items: ['item 1', 'item 2', 'item 3'],
deletedItems: ['item 4', 'item 5']
};
}
removeItem = (number) => {
const itemsState = this.state.items;
const deletedItemsState = this.state.deletedItems;
const itemToBeDeleted = itemsState[number];
deletedItemsState.push(itemToBeDeleted);
itemsState.splice(number, 1);
this.setState({
items: itemsState
}, () => {
console.log(this.state);
});
}
render() {
return (
<div>
Items:
<ul>
{this.state.items.map((item, i) => <li>{item} <button onClick={this.removeItem.bind(this, i)}>Remove</button></li>)}
</ul>
Deleted Items:
<ul>
{this.state.deletedItems.map(item => <li>{item}</li>)}
</ul>
</div>
);
}
}
ReactDOM.render( < MyApp / > , document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
答案 1 :(得分:0)
这不是处理应用中状态更改的正确方法。
例如,这一行
const itemsState = this.state.items;
它创建一个指向this.state.items的变量itemsState。因此,您对itemsState所做的任何更改都将在您的state.items中进行更改。这会改变您的数据。
最佳做法是使用诸如immutability-helper之类的库来进行状态更新,或者将状态对象克隆到变量中,然后对它们执行突变。完成后,最后使用setState()更新状态。
以下是一段代码片段,介绍如何使用 Object.assign()进行克隆。如您在代码段中所见,这不会改变原始状态变量。
var state = {
items: ['item 1', 'item 2', 'item 3'],
deletedItems: ['item 4', 'item 5']
};
function removeItem(number) {
const itemsState = Object.assign([], this.state.items);
const deletedItemsState = Object.assign([], this.state.deletedItems);
const itemToBeDeleted = itemsState[number];
deletedItemsState.push(itemToBeDeleted);
itemsState.splice(number, 1);
//this.setState({ items: itemsState });
console.log(state);
}
removeItem(1);
&#13;