03-状态
# 一,状态
# 1,状态在类组件中的使用
前面我们定义的数据,都是普通变量,并不是状态,现在我们开始学习state。
安装一个react的调试插件,如下:
使用之,如下:
代码如下:
浏览器中效果如下 :
尝试直接修改状态,如下:
当我们点击时,报错了,如下:
打印出this是und,如下:
此时,就需要显示绑定this,如下:
绑定this后,我们再去修改状态,如下:
直接修改状态,不推荐,因为修改状态的目的还需要让模板刷新,有个专属API,叫setState,是专门来用来修改状态的,如下 :
我们现在的想法是让它每一次都+1,如下:
虽然++在前是OK的,但是不推荐,原因是修改了两次num,一次是直接修改,一次是间接修改。最好的处理方法如下:
this.setState是异步的,在React18中,永远是异步的,在React18之前,有可能是同步,有可能是异步,测试如下:
上面的修改状态的写法,还不是很优雅,比较优雅的写法,如下:
上在的写法,可以简写,如下:
浏览器测试如下:
this.setState有两种写法:
- this.setState({}, callback) 在修改状态时,当新值与旧值无关时,推荐使用这种写法,callback表示当状态修改后,自动执行,当状态修完后,有一些业务逻辑放到callback中。
- this.setState((state, props)=>({}), callback) 当新值与旧值有关时,新值由旧值计算而来,形参state永远表示旧值,建议使用这种写法。callback表示当状态修改后,自动执行,当状态修完后,有一些业务逻辑放到callback中。
上面我们讲了,在类组件中如何定义状态,如何使用状态,如何修改状态。
# 2,修改状态的同步和异步问题
在React18之前,React16和React17,this.setState在合成事件中,是异步的。在宏任务(定时器),Promise.then中是同步的。所谓的React合成事件是指on*系列事件,生命周期函数。
在React18中,this.setState任务时候都是异步的。代码如下:
总结:
- 在React18之前,setState写在宏任务中,或Promise.then中,它是同步的。
- 在React18之前,setSteate写在合成事件中,是异步的。
- 在React18中,不管setState写在哪里,永远都是异步的。
在V18中,setState一定是异步的,如下:
如果放在定时器,如下:
你要想看一下修改后状态的结果,如下:
看一下如下代码,分析结果,如下:
为什么是V18版本中,把this.setState设计成异步的?
答:为了性能优化。在V18中,无论this.setState在哪里,都是异步的,这种特性,叫”并发模式“
this.setState会自动合并,如下:
看再如下代码:
# 3,初识事件绑定
看如下事件绑定:
上面的写法,不完美,因为在监听器中不能获取到this。this是und。解决办法有两种:
- 利用ES5中的bind中手动绑定this
- 利用ES6中的箭头函数自动绑定this
ES5绑定代码如下:
浏览器测试如下:
使用ES6中的箭头函数自动绑定this,代码如下:
浏览器中测试如下:
想获取事件对象,如下:
# 4,状态在函数组件中的使用
函数组件中是不能定义状态,但是配合hook可以定义状态,hook类似于vue3中的组合式API,在React16.8中就有了,React16.8有三四年,hook也有三四年,只不过,最近两年hook才火起来了。
直接上代码,如下:
看下面的写法,有没有问题:
setNum是同步还是异步,如下:
setNum是同步还是异步,在不同的版本中是不一样的,总结如下:
- 在V18之前,在合成事件中是异步的,在宏任务和promise.then中是同步的。
- 在V18中,无论在哪里都是异步的。
setNum中,是没有callback。setNum还有一种写法,如下: