我有两个问题,state
这里是什么?
一个实例属性,就像this.state = {value: 0};
在构造函数中设置一样。它正在使用目前处于第 2 阶段的公共类字段提案。(也是increment
和decrement
,它们是实例字段,其值为箭头函数,因此它们关闭了this
。)
那是局部变量吗?
不。
prevState 来自哪里?为什么在 setState 中使用箭头函数?只做 this.setState({value:'something'}) 不是很容易吗?
从文档:
setState()
为了提高性能,React 可以将多个调用批处理为单个更新。
因为this.props
和this.state
可能会异步更新,所以您不应该依赖它们的值来计算下一个状态。
例如,此代码可能无法更新计数器:
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
要修复它,请使用setState()
接受函数而不是对象的第二种形式。该函数将接收先前的状态作为第一个参数,并将应用更新时的 props 作为第二个参数:
// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
...这正是引用的代码所做的。这是错误的:
// Wrong
increment = () => {
this.setState({
value: this.state.value + 1
});
};
...因为它依赖于 的状态this.state
,上面告诉我们不要这样做;所以引用的代码是这样做的:
increment = () => {
this.setState(prevState => ({
value: prevState.value + 1
}));
};
这里证明 React 可能以一种不明显的方式批量调用,以及为什么我们需要使用 的回调版本setState
:在这里,我们有increment
并且每次点击decrement
被调用两次而不是一次(一次通过按钮,一次通过包含按钮的跨度)。单击+
一次应该将计数器增加到 2,因为increment
被调用了两次。但是因为我们没有使用 的函数回调版本setState
,所以它没有:increment
因为我们使用了一个陈旧的this.state.value
值,所以这些调用之一变成了一个空操作:
class Counter extends React.Component {
state = { value: 0 };
increment = () => {
/*
this.setState(prevState => ({
value: prevState.value + 1
}));
*/
console.log("increment called, this.state.value = " + this.state.value);
this.setState({
value: this.state.value + 1
});
};
fooup = () => {
this.increment();
};
decrement = () => {
/*
this.setState(prevState => ({
value: prevState.value - 1
}));
*/
console.log("decrement called, this.state.value = " + this.state.value);
this.setState({
value: this.state.value - 1
});
};
foodown = () => {
this.decrement();
};
render() {
return (
<div>
{this.state.value}
<span onClick={this.fooup}>
<button onClick={this.increment}>+</button>
</span>
<span onClick={this.foodown}>
<button onClick={this.decrement}>-</button>
</span>
</div>
)
}
}
ReactDOM.render(
<Counter />,
document.getElementById("react")
);
<div id="react"></div>
<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>
使用函数回调,它可以正常工作(没有调用increment
变为无操作):
class Counter extends React.Component {
state = { value: 0 };
increment = () => {
this.setState(prevState => {
console.log("Incrementing, prevState.value = " + prevState.value);
return {
value: prevState.value + 1
};
});
};
fooup = () => {
this.increment();
};
decrement = () => {
this.setState(prevState => {
console.log("Decrementing, prevState.value = " + prevState.value);
return {
value: prevState.value - 1
};
});
};
foodown = () => {
this.decrement();
};
render() {
return (
<div>
{this.state.value}
<span onClick={this.fooup}>
<button onClick={this.increment}>+</button>
</span>
<span onClick={this.foodown}>
<button onClick={this.decrement}>-</button>
</span>
</div>
)
}
}
ReactDOM.render(
<Counter />,
document.getElementById("react")
);
<div id="react"></div>
<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>
在这种情况下,当然,我们可以查看该render
方法并说“嘿,increment
在单击过程中会被调用两次,我最好使用 的回调版本setState
。” 但是,与其假设this.state
在确定下一个状态时使用它是安全的,最好的做法是不要假设它。在复杂的组件中,很容易以 mutator 方法的作者可能没有想到的方式使用 mutator 方法。因此 React 作者的声明:
因为this.props
和this.state
可能会异步更新,所以您不应该依赖它们的值来计算下一个状态。