React中的state与setState并不是想的那么简单
文章目录
前言
学习React也有那么久了,遇到一些很奇怪的错误,和一些很奇怪的坑,特别是state和setState中的坑,让我久久不能忘记,于是写下了这篇,记录自己的错误与自己填的坑,供大家参考,如有错误,欢迎指正~
管理好state并不是那么简单
这是初学者开发React项目会遇到最大的坑之一,因为要良好地使用state需要转变很多思想,其实主要也是要深度理解React中state较为复杂的机制,下面是我遇到的这些坑:
- 不能直接更新状态,如:this.state.color=”red”;
- setState是异步的,不能在setState后直接使用新的state
- 不能在setState里面调用this.state
- setState是合并调用的,并不是单个setState单次调用
对于以上四点,我们逐个来分析,
1.正确改变state的姿势
刚刚学习React的时候,受于惯性思维,比如想要改变state的值,直接像下面一样改变:1
this.state.comment = 'Hello'; //wrong
这会导致什么情况呢?我们用一个例子来展示:
1 | class App extends React.Component { |
一般我们觉得,按钮点击后,this.state.color就成了”green”,定时器里面输出green,然后p标签的内容也变成green,不用你亲自试,我做了个gif图表示:

我们惊讶的发现p标签中的内容并没有变化,但是this.state.color确实改变了呀。我们不难分析出,如果使用this.state.color=“green”来改变state的话,state确实会改变,但是并没有驱动组件进行更新渲染,而使用setState就正常渲染,这说明this.setState()做了两件事:1. 改变state值 2. 驱动组件重新渲染。所以再次强调切勿用JavaScript改变对象的值一样来改变React的state。
2. this.setState(),更新是异步的
setState是异步的,不能在setState后直接使用新的state,比如像下面一样:
1 | setColor(){ |
这也是我们常常遇到的问题,但是很多时候,有必须要在setState后面直接使用最新的this.state怎么办?我总结了三种办法:
- 设置一个定时器
1 | setColor(){ |
这都不难理解,在eventloop中打印this.state.color的次序排在this.setState后面,因此能获得最新值
- 使用this.setState()的回调函数
1 | setColor(){ |
这是React为了方便很多喜欢用回调函数的小伙伴们创造的福利~
3. 不能在setState里面调用this.state
相信很多小伙伴会写出这样的代码,其实这是很容易导致bug的,因为从第二点我们可以看书,this.state可能是异步更新的,所以不能依靠他来计算下一个值。
1 | this.setState({ |
4. setState是合并调用的,并不是单个setState单次调用
这个问题确实让我想了很久,但是又不知道为什么,当初遇到的问题是下面代码,后来看了github一个小伙伴的讲解,说是setState是合并调用,并不是分开来调用的。
1 | constructor(props){ |
问题: 触发一次increment后,count的值是多少
答案:2
别不信,下面是我运行的gif图:
这是什么导致的呢?React官方的解释是为了性能优化,一次性将“本轮的setState”合并一起调用,什么意思呢?不知道你用过Object.assign()没有,如下:
1 | Object.assign({}, { a: 2, b: 3 }, { a: 1, c: 4 }); //{a:1,c:4,b:3} |
没错,setState也是这么做的,如下:
1 | Object.assign({count: countNum+5},{count: countNum+1}) |
这么一说,就好理解了,React官方这么做也不是没有道理的,如果你注重代码质量,就不会在同一时段重复在setState中改变同一个state。
那么问题来了,我偏要这样怎么办?那我们就得“人为”地将这两次setState分开来,定时器就是一个比较hack的方案:
1 | increment(){ |
总结
其实我一直认为自己遇到的坑都不能叫坑,只是自己没有认真阅读文档而已,也反应出自己浮躁的心情,急于求成,这是件非常可怕的事情,听过这么一句话:“好的代码,都是用时间熬出来的”,所以在这次总结后,我将会就React文档再次认真阅读。
Truth never fears investigation :)