setState参数
setState第一个参数传递函数
import React,{ Component } from 'react';
class A extends Component{
state = {
A: 1,
}
onChangeA = ()=>{
this.setState((state,props)=>{
A: state.A + 1
})
console.log('setState之后',this.state.A) // 1 无法获取到最新的值
}
rebder(){
const { A } = this.state
return(
<div>
<div>A的值: { A ]</div>
<button onClick={ this.onChangeA }>改变A的值,第一个参数为函数</button>
</div>
)
}
}
setState第一个参数传递对象
import React,{ Component } from 'react';
class A extends Component{
state = {
A: 1,
}
onChangeA = ()=>{
const A = this.state.A + 1;
this.setState({
A: A
})
console.log('setState之后',this.state.A) // 1 无法获取到最新的值
}
rebder(){
const { A } = this.state
return(
<div>
<div>A的值: { A ]</div>
<button onClick={ this.onChangeA }>改变A的值,第一个参数为对象</button>
</div>
)
}
}
setState第二个参数Callback
setState第二个参数Callback: 何时执行: 在状态更新之后,界面更新之前调用
import React,{ Component } from 'react';
class A extends Component{
state = {
A: 1,
}
onChangeA = ()=>{
const A = this.state.A + 1;
this.setState({
A: A
},()=>{
/*
这个回调函数执行:
在状态更新之后,界面更新之前调用
*/
console.log('setState之后',this.state.A) // 2 在回调函数中可以获取到最新的值
})
}
rebder(){
const { A } = this.state
return(
<div>
<div>A的值: { A ]</div>
<button onClick={ this.onChangeA }>改变A的值,第一个参数为对象</button>
</div>
)
}
}
总结
- 传递对象的方式是传递函数的简写形式
- 如果新状态不依赖于原状态 ===> 使用对象形式
- 如果新状态依赖于原状态 ===> 使用函数形式
- 如果需要在setState()后获取最新的状态,在第二个参数callback回调函数中读取
- 这个callback在状态更新之后,界面更新之前(render)执行.
setState更新是同步还是异步?
react中setState({})是基于事务的机制
- 执行setState()的位置
- 在react控制的回调函数中: 生命周期钩子/react事件监听回调(onClick、onKeyDown不是原生的DOM事件)
- 非react控制的异步回调函数中: 定时器回调 / 原生事件回调 / Promise回调 / ..
- 异步 OR 同步?
- react相关回调中: 异步
- 其他异步回调中: 同步
在react生命周期钩子中或者react事件监听中(异步)
import React,{ Component } from 'react';
class A extends Component{
state = {
A: 0
}
clickOne = ()=>{
console.log('update1 setState()之前'+this.state.A); // update1 setState()之前1
this.setState(state=>({ A:state.A+1 }));
console.log('update1 setState()之后'+this.state.A); // update1 setState()之后1
};
componentDidMount(){
console.log('componentDidMount setState()之前'+this.state.A); // componentDidMount setState()之前0
this.setState(state=>({ A:state.A+1 }));
console.log('componentDidMount setState()之后'+this.state.A); // componentDidMount setState()之后0
}
render(){
return(
<div>
{ this.state.A }
<div onClick={ this.clickOne }>事件中</div>
</div>
)
}
}
在非react回调中
class A extends Component{
state = {
A: 0
};
/*
* 定时器, 同步的
* */
setTimeClick = ()=>{
setTimeout(()=>{
console.log('setTimeout setState()之前'+this.state.A);
this.setState(state=>({ A:state.A+1 }));
console.log('setTimeout setState()之后'+this.state.A);
/*
* 打印结果
setTimeout setState()之前1
render()2
setTimeout setState()之后2
* */
},300)
}
/*
* 原生事件, 同步的
* */
nativeClick = ()=>{
const h2 = this.refs.count
h2.onclick = ()=>{
console.log('onclick setState()之前'+this.state.A);
this.setState(state=>({ A:state.A+1 }));
console.log('onclick setState()之后'+this.state.A);
}
/*
* 打印结果
* componentDidMount setState()之前0
render()1
componentDidMount setState()之后1
* */
}
/*
* promise, 在await后面执行的也算
* */
promiseClick = ()=>{
Promise.resolve().then(()=>{
console.log('Promise setState()之前'+this.state.A);
this.setState(state=>({ A:state.A+1 }));
console.log('Promise setState()之后'+this.state.A);
})
/*
* 打印结果
* Promise setState()之前0
render()1
Promise setState()之后1
* */
};
render(){
const { A } = this.state
console.log('render()'+A)
return(
<Card>
<div > A的值: <h2 ref="count">{ A } </h2></div>
<Button onClick={ this.setTimeClick }>定时器</Button>
<Button onClick={ this.nativeClick }>原生事件</Button>
<Button onClick={ this.promiseClick }>Promise事件中</Button>
</Card>
)
}
}
对于setState(fn)的调用
多次调用异步setState(),render必然只执行一次.
函数的模式setState(fn): 更新多次状态,但只调用一次render()更新界面 -- 状态更新没有合并,但是界面更新合并了
状态更新没有合并,界面更新合并了
class A extends Component{
state = {
A: 0
}
clickOne = ()=>{
this.setState(state=>({ A:state.A+1 }));
this.setState(state=>({ A:state.A+1 }));
this.setState(state=>({ A:state.A+1 }));
}
render(){
return(
<div>
{ this.state.A } // 最终页面输出3
<div onClick={ this.clickOne }>事件中</div>
</div>
)
}
}
对于setState({})的调用
多次调用异步setState(),render必然只执行一次.
对象的模式setState({}): 合并更新一次状态,只调用一次render()更新界面 --- 状态更新和界面更新都合并了
状态和界面都合并了
class A extends Component{
state = {
A: 0
}
clickOne = ()=>{
this.setState({ A:this.state.A+1 });
this.setState({ A:this.state.A+1 });
this.setState({ A:this.state.A+1 });
}
render(){
return(
<div>
{ this.state.A } // 最终页面输出3
<div onClick={ this.clickOne }>事件中</div>
</div>
)
}
}
对于setState({})和setState(fn)混用
只要最后一次调用的是对象模式--不管之前调用何种模式,都合并
只要最后一次调用的是函数模式--不管之前是对象模式还是函数模式,只要遇到对象模式,都合并之前的,然后累积函数模式的(状态更新)
class A extends Component{
state = {
A: 0
}
clickOne = ()=>{
this.setState({ A:this.state.A+1 });
this.setState({ A:this.state.A+1 });
this.setState(state=>({ A:state.A+1 }));
this.setState({ A:this.state.A+1 }); // state.A截止这里为1
this.setState(state=>({ A:state.A+1 })); // 从这里开始累加 //2
this.setState(state=>({ A:state.A+1 })); // 3
}
clickTwo = ()=>{
this.setState({ A:this.state.A+1 });
this.setState(state=>({ A:state.A+1 }));
this.setState(state=>({ A:state.A+1 }));
this.setState({ A:this.state.A+1 });
this.setState({ A:this.state.A+1 }); // 1
}
render(){
return(
<div>
{ this.state.A } // 最终页面输出3
<div onClick={ this.clickOne }>事件中</div>
<div onClick={ this.clickTwo }>事件中</div>
</div>
)
}
}
总结
关于异步的setState()
-
- 多次调用异步setState(),render必然只执行一次.
-
- 对于setState(fn)和setState({})的理解
- 函数的模式setState(fn): 更新多次状态,但只调用一次render()更新界面 -- 状态更新没有合并,但是界面更新合并了
- 对象的模式setState({}): 合并更新一次状态,只调用一次render()更新界面 --- 状态更新和界面更新都合并了
- 混合模式(既有setState(fn)又有setState({}))
- 只要最后一次调用的是对象模式--不管之前调用何种模式,都合并
- 只要最后一次调用的是函数模式--不管是对象模式还是函数模式,只要遇到对象模式,都合并之前的,然后累积函数模式的(状态更新)
关于同步的setState()
- 在非react控制的回调函数中,setState()是同步的,只要执行setState(),界面(render)立马更新,然后在执行其他的代码.