在下面的示例中,我使用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 })
似乎不应该引起重新渲染
答案 0 :(得分:2)
摘自文档:setState
setState()将始终导致重新渲染,除非shouldComponentUpdate()返回false。
这意味着this.setState({});
导致重新渲染,无论您是否将更改作为参数传递
答案 1 :(得分:1)
您错了:
this.setState({}); // this will do nothing.
您期望状态应该用空对象更新。但这不是。
使用setState方法时,它期望属性更新。但是,由于您没有为setState提供任何属性,因此它将什么都不做。但是它仍然会通过setState性质重新呈现您的组件。
更新:针对您的查询
编辑:我也想指出(因为很多答案都涉及到我传递一个空对象这一事实),如果我这样调用setState,则该组件将被重新渲染(并更新):
this.setState({ results: this.state.results })
似乎不应该引起重新渲染
内部反应表明,当您尝试使用完全相同的状态更新状态时,它类似于this.state.results
。因此,没有什么要重新渲染的。但是,当将setState与空对象一起使用时,React会闪烁其状态,以便进行重新渲染。
从docs阅读此注释:
注意
避免将道具复制到状态中!这是一个常见的错误:
constructor(props) {
super(props);
// Don't do this!
this.state = { color: props.color };
}
问题在于,这既不必要(您可以直接使用this.props.color
),又会产生错误(对颜色道具的更新不会反映在状态中)。
答案 2 :(得分:1)
根据文档, setState()将始终导致重新渲染,除非shouldComponentUpdate()返回false。 您可以将 render()函数视为创建React元素树。在下一个状态或道具更新时,该render()函数将返回不同的React元素树(虚拟DOM )。
在任何时候,反应库维护两个虚拟DOM副本。
触发对 setState()的请求时,React将创建一个新树,其中包含组件中的反应性元素(以及和更新后的状态)。 通过与前一棵树的元素进行比较,该树用于确定组件的UI应如何响应状态变化而更改。
虚拟DOM,然后通过称为对帐的过程与实际DOM同步。
对于突变,不进行直接突变可以避免项目中不必要的错误,因为 setState()是异步的,这意味着您不能期望setState立即更新状态(它批量执行),因此以前的任何突变都可以被先前的setState状态更新操作覆盖。
参考-
答案 3 :(得分:0)
当调用this.setState
时,基本上React会将我们传递给该函数的参数与旧的this.state
合并以产生新的状态值。例如:
this.state = Object.assign({}, this.state, passedParam);
因此,在以上代码段中,每次调用this.setState({});
时,都会创建一个新的状态对象,该对象将重新呈现Component。