【发布时间】:2020-10-09 19:40:19
【问题描述】:
在下面的示例中,我使用 ES6 Map 作为 React 中的状态值:
class App extends React.Component {
constructor(props) {
super(props);
const results = new Map();
results["group1"] = [{ value: "..." }, { value: "..." }];
this.state = { results };
}
onUpdateClick(i) {
this.state.results["group1"][i].value = i;
this.setState({});
}
onResetClick(i) {
this.state.results["group1"][i].value = "...";
this.setState({});
}
render() {
const { results } = this.state;
return (
<div>
{results["group1"].map((r, i) => (
<div>
{r.value}
<button onClick={e => this.onUpdateClick(i)}>update</button>
<button onClick={e => this.onResetClick(i)}>reset</button>
</div>
))}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("container"));
<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='container'></div>
当您单击按钮时,我会直接更新 Map,然后在不带参数的情况下调用 setState。我不制作地图的克隆/深层副本。根据我对 React 文档的理解,这应该不起作用,并且在文档中明确警告:
永远不要直接改变 this.state,因为之后调用 setState() 可能会替换你所做的改变。将 this.state 视为不可变的
(https://reactjs.org/docs/react-component.html#state)
文档还指出比较是浅的,所以用空对象调用肯定不会导致合并,因此不会重新渲染?
为什么这个例子有效?
(我还应该注意,我也使用 React v16.9.0 重现了这种行为)
编辑: 我还想指出(因为许多答案是指我传递一个空对象的事实)如果我像这样调用 setState,组件将被重新渲染(和更新):
this.setState({ results: this.state.results })
这似乎不应该导致重新渲染
【问题讨论】:
-
您不是在没有参数的情况下调用
setState,而是给它一个空对象。 React 将尝试更新,但由于空对象不包含任何与先前状态合并的键,因此它会保留您的突变。 -
谢谢@BrianThompson。我还要注意: setState({ results: this.state.results }) 也会导致重新渲染,在这种情况下我再次问这个问题......
标签: javascript reactjs setstate