持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第33天,点击查看活动详情
setState的花样用法
场景:点击按钮改变a的值。
state={a:0,b:0,c:0}
handleClick = ()=>{
console.log(this)//App=>类组件实例
}
render(){
return (
<div>
<h1>{this.state.a}</h1>
{/*onClick onChange : 合成事件 对事件进行包装 (事件代理 委托)*/}
<button onClick={this.handleClick}>click</button>
</div>
)
}
复制代码
方法1
this.state.a = 1
console.log(this.state.a); //1
复制代码
只改变了a的状态值,但是没有触发render渲染页面。
方法2
//3 setState : 改变值 & render
this.setState({
a:1
})
复制代码
使用setState改变a的状态值,且setState默认自动触发render。
方法3
this.setState({
a:1
})
console.log(this.state.a); // 0
复制代码
由于setState是异步函数,所以在执行同步语句打印a时,仍然是0.但setState可以自动触发render
方法4
this.setState({a:1})
this.setState({a:this.state.a+1},()=>{
console.log('callback',this.state.a); //1。不依赖上次setState的值。
})
console.log(this.state.a); // 0 异步原因
复制代码
在setState中写箭头函数获取异步值,在方法3的基础上回调获取。
方法5
this.setState({a:1}) //1
this.setState({a:this.state.a+2})//2
this.setState({a:this.state.a+3})//3
复制代码
所以a的值最后被更改为3. react有性能优化机制,即使render了三次a值,但内部也会等a更新完再去执行render渲染a状态。所以,即使改变了三次a值,也只执行一次render。
方法6.
this.setState({a:1})
this.setState((preState,props)=>{
return {a:preState.a+1} //1
})
this.setState((preState,props)=>{
return {a:preState.a+1} //2
})
this.setState((preState,props)=>{
return {a:preState.a+1}//3
},()=>{
console.log('callback',this.state.a); //3
})
复制代码
观察上一段代码,每个setState函数中都有一个回调函数返回一个状态。其实可以将上述代码理解为每一个setState依赖于上一个setState返回的状态,相当于在一个栈中,最上面的执行到最下面,且互相依赖。也很好的解决了异步问题,实现了累加依赖上次计算结果的自由。
可以将方法5和6进行对比,从异步到解决累加隐患,形成依赖。
综上所述,可以获得规律:
setState({}) log//异步,无法打印获取值,可以render值。
setState({},()=>{log}) //连续几个setState也不会产生依赖,可以打印获取值,可以render值。
setState(()=>{},()=>{log}) //连续几个setState会产生依赖,可以打印获取值。
复制代码
9.13更新
setState为同步时的情况
场景1:
setTimeout(() => {
// console.log(this, "this"); //箭头函数 =》 this指向App
// this.setState({ a: 1 });
// console.log(this.state.a, "a"); //1
}, 1000)
复制代码
已知setState为异步事件,但如果发生在定时器內部,那么react就会默认成为同步时间,所以打印的结果为更改后的值。
场景2:
handleClick2 = () => {
console.log(this, "this");//App
this.setState({ a: 1 })
console.log(this.state.a, "a"); //0
}
<button id="button2">click2</button>
document.getElementById("button2"), addEventListener('click', this.handleClick2)
复制代码
利用原生获取dom节点触发方法时,setState也是同步方法。即打印的为更改后的值。
handleClick2 = () => {
console.log(this, "this");//App
this.setState({ a: 1 })
this.setState({ b: 1 })
this.setState({ c: 1 })
console.log(this.state.a, "a"); //0
}
<button id="button2">click2</button>
document.getElementById("button2"), addEventListener('click', this.handleClick2)
复制代码
上面代码更改了三次值,由于因为原生事件setState已经变为同步代码,所以render会重新渲染3次。
面试题:setState为同步/异步?
答案:不确定。当只用于合成事件时,生命周期钩子函数中时,为异步。
当用于定时器,用于原生dom方法时,为同步。
且,当异步时可以利用回调函数解决异步问题。