我是React的新手,只是对setState方法有疑问。假设我们有一个组件:
class MyApp extends React.Component {
state = {
count: 3
};
Increment = () => {
this.setState((prevState) => ({
options: prevState.count + 1)
}));
}
}
那么为什么我们必须在setState方法中使用prevState?我们为什么不能这样做:
this.setState(() => ({
options: this.state.count + 1)
}));
答案 0 :(得分:2)
这里每个人都知道state:prevstate.counter + 1 ..我们也可以使用state:this.state.counter + 1来做到这一点。这不是我认为使用prevstate的方式。当我推入现有状态时,我在数组中遇到问题,但是我第二次阻止更改
答案 1 :(得分:1)
两个签名都可以使用,唯一的区别是,如果您需要根据先前的状态更改状态,则应使用this.setState(function)
,它将为您提供快照(prevState
)。以前的状态。但是,如果更改不依赖于其他任何先前的值,则建议使用较短的版本this.setState({prop: newValue})
this.setState(prevState =>{
return{
...state,
counter : prevState.counter +1
}
})
this.setState({counter : 2})
答案 2 :(得分:0)
class MyApp extends React.Component {
state = {
count: 0
};
Increment = () => {
this.setState(prevState => ({
count: prevState.count + 1
}));
this.setState(prevState => ({
count: prevState.count + 1
}));
this.setState(prevState => ({
count: prevState.count + 1
}));
this.setState(prevState => ({
count: prevState.count + 1
}));
};
IncrementWithoutPrevState = () => {
this.setState(() => ({
count: this.state.count + 1
}));
this.setState(() => ({
count: this.state.count + 1
}));
this.setState(() => ({
count: this.state.count + 1
}));
this.setState(() => ({
count: this.state.count + 1
}));
};
render() {
return (
<div>
<button onClick={this.IncrementWithoutPrevState}>
Increment 4 times without PrevState
</button>
<button onClick={this.Increment}>
Increment 4 times with PrevState
</button>
<h1>Count: {this.state.count}</h1>
</div>
);
}
}
我只是为您提供了一个示例,以说明“ React可能批处理多个setState()...”的含义,以及在上述情况下为什么应使用prevState的原因。
首先,尝试猜测 ,当您同时单击两个按钮时,Count
的结果应该是什么...如果您认为count
将在两个按钮上单击时都增加4,则不正确;)
为什么?因为在IncrementWithoutPrevState
方法中 ,因为存在多个setState
调用,所以React批量处理了所有这些调用并仅在{{1 }},因此在此方法上一次调用state
时,setState
尚未更新,其值仍与进入setState
方法之前的值相同,因此结果状态将包含递增1的this.state.count
。
IncrementWithoutPrevState
方法,则 现在:
再次有多个count
调用,React将它们分批处理,这意味着实际状态将在上一次调用Increment
中更新,但是setState
将始终包含修改后的setState
在最近的prevState
通话中。由于state
的值已经增加了3次,直到最后一次调用setState
,所以结果previousState.count
将包含递增4的计数值。
答案 3 :(得分:0)
如果您多次调用一个函数以在单个render()
函数调用中更改状态属性的值,则没有prevState机制,更新的值将不会在不同的调用之间传递。
second(){
this.setState({ // no previous or latest old state passed
sec:this.state.sec + 1
}, ()=>{
console.log("Callback value", this.state.sec)
})
}
fiveSecJump(){ // all this 5 call will call together
this.second() // this call found sec = 0 then it will update sec = 0 +1
this.second() // this call found sec = 0 then it will update sec = 0 +1
this.second() // this call found sec = 0 then it will update sec = 0 +1
this.second() // this call found sec = 0 then it will update sec = 0 +1
this.second() // this call found sec = 0 then it will update sec = 0 +1
}
render() {
return (
<div>
<div> Count - {this.state.sec}</div>
<button onClick ={()=>this.fiveSecJump()}>Increment</button>
</div>
)
}
最后sec的值将为1,因为调用是异步的,与c ++ / c#或java等高级编程语言不同,在Java中,总是有一个主函数来维护主线程。
因此,如果要使fiveSecJump()
函数正常工作,则必须通过向其传递箭头函数来提供帮助。 prevState。 prevState不是关键字或成员函数,您可以在此处编写任何单词,例如oldState,stackTopState,lastState。它将转换为可完成您所需工作的通用函数。
class Counter extends Component {
constructor(props){
super(props)
this.state = {
sec:0
}
}
second(){
this.setState(prevState =>({
sec:prevState.sec + 1
}))
}
fiveSecJump(){
this.second() // this call found sec = 0 then it will update sec = 0 +1
this.second() // this call found sec = 1 then it will update sec = 1 +1
this.second() // this call found sec = 2 then it will update sec = 2 +1
this.second() // this call found sec = 3 then it will update sec = 3 +1
this.second() // this call found sec = 4 then it will update sec = 4 +1
}
render() {
return (
<div>
<div> Count - {this.state.sec}</div>
<button onClick ={()=>this.fiveSecJump()}>Increment</button>
</div>
)
}
}
export default Counter
答案 4 :(得分:0)
//Here is the example to explain both concepts:
import React, { Component } from 'react'
export default class Counter extends Component {
constructor(props) {
super(props);
this.state = { counter: 0 }
}
increment() {
this.setState({counter:this.state.counter+1})
}
increment3() {
this.increment();
this.increment()
this.increment()
}
render() {
return (
<div>
count-{this.state.counter}
<div>
<button onClick={() => this.increment3()}>Increment</button>
</div>
</div>
)
}
}
在这种情况下,当我们点击 Increment 按钮时,输出将呈现到 UI 中的是 count-0 而不是 count-3因为 react 将所有状态调用组合在一个状态调用中,并且不会在每次递增的调用中都携带更新的值。如果我想根据以前的值更新值,请使用下面提到的代码。
import React, { Component } from 'react'
export default class Counter extends Component {
constructor(props) {
super(props);
this.state = { counter: 0 }
}
increment() {
this.setState((prevState=>({counter:prevState.counter+1})))
}
incremental() {
this.increment();
this.increment()
this.increment()
}
render() {
return (
<div>
count-{this.state.counter}
<div>
<button onClick={() => this.incremental()}>Increment</button>
</div>
</div>
)
}
}
在这种情况下,输出将是 count-3 而不是 count-0
答案 5 :(得分:0)
@samee 的回答很棒,帮助了我。我想重温这个话题来解决 React 函数组件,只是因为这是我目前正在研究的内容。
以下示例说明了为什么如果新状态是使用先前状态计算的,您可能希望使用 prevState。
function App() {
const [developer, setDeveloper] = useState({
yearsExp: 0,
});
function handleYearsExp() {
setDeveloper((prevState) => ({
yearsExp: prevState.yearsExp + 1, //increments by 1
}));
setDeveloper((prevState) => ({
yearsExp: prevState.yearsExp + 1, //increments by another 1
}));
}
return (
<>
<button onClick={handleYearsExp}>Increment Years</button> {/* will increment by 2 */}
<p>
I am learning ReactJS and I have {developer.yearsExp} years experience
</p>
</>
);
}
这是没有将 prevState
函数传递给 setState
的代码。请注意,第一个 setState
函数基本上被忽略了。
function App() {
const [developer, setDeveloper] = useState({
yearsExp: 0,
});
function handleYearsExp() {
setDeveloper({
yearsExp: developer.yearsExp + 1, // is ignored
});
setDeveloper({
yearsExp: developer.yearsExp + 1, //increments by 1
});
}
return (
<>
<button onClick={handleYearsExp}>Increment Years</button> {/* will only increment by 1 */}
<p>
I am learning ReactJS and I have {developer.yearsExp} years experience
</p>
</>
);
}
参考文献: