我有 2 个问题,什么是state
here?
实例属性,例如设置this.state = {value: 0};
在构造函数中。它正在使用公开课领域提案 https://tc39.github.io/proposal-class-public-fields/目前处于第二阶段。(也是如此increment
and decrement
,它们是实例字段,其值为箭头函数,因此它们闭合this
.)
这是一个局部变量吗?
No.
prevState 从哪里来?为什么setState要用箭头函数?仅仅执行 this.setState({value:'something'}) 不是很容易吗?
From 文档 https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous:
React 可以批处理多个setState()
调用单个更新以提高性能。
Because this.props
and 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
and decrement
被叫twice每次点击而不是一次(一次通过按钮,一次通过包含按钮的跨度)。点击+
once应该将计数器增加到 2,因为increment
被调用两次。但是因为我们还没有使用函数回调版本setState
,它没有:其中一个调用increment
变成空操作,因为我们使用的是陈旧的this.state.value
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
当确定下一个状态时,最佳实践是not假设。在复杂的组件中,可以很容易地以 mutator 方法的作者可能没有想到的方式使用 mutator 方法。因此 React 作者的声明是:
Because this.props
and this.state
可以异步更新,你不应该依赖它们的值来计算下一个状态.