世界上最伟大的投资就是投资自己的教育

全场限时 5 折

首页JavaScript
xiaohesong · 凡人

react 之 setSate 的`坑`

xiaohesong发布于5818 次阅读
  • setState

今天发现有很多文章在说setState的坑,吐槽之声也不少.其实我就碰到过一个.

setState不会立即改变数据

// name is ""
this.setState({
    name: "name"
})
console.log(`name is ${this.state.name}`)

这段代码没有按我的预料输出name.

所以如果需要获取,就需要在回调函数里去做.

this.setState({
    name: "name"
}, () => {
  console.log(`name is ${this.state.name}`)
})

这样才会如你所预料那般的输出.

对于上面的这个问题倒是还好.因为setState是放在一个队列里异步去处理的, 所以在没有成功改变之前,输出的就是之前的值.
在回调里显示正确的数据,那是因为callback的原因.

setState多次,re-render一次

这个是我始料未及的了,我一直以为每次setState都会造成一次re-render.其实并不是这样.

componentDidMount(){
  this.setState((prevState, props) => ({count: this.state.count + 1})) // 1
  this.setState((prevState, props) => ({count: this.state.count + 1})) // 2
  this.setState((prevState, props) => ({count: this.state.count + 1})) // 3
  this.setState({name: "xiaohesong"}) // 4
}

render(){
  console.log("render")
  return(<h1>SetState</h1>)
}

可以发现,这里只会出现render两次,而不是想象中的4+1(初始化的render).
WTF! Why?

好吧,还是得寻找原因不是?

我们之前说他是塞进一个队列里去做异步的处理的,就是说他是把我们这4setState操作放到了一个队列里,然后 batch 操作.啥啥啥?恩,还是来代码阐述下比较好.

  this.setState((prevState, props) => ({count: this.state.count + 1})) // 1
  this.setState((prevState, props) => ({count: this.state.count + 1})) // 2
  this.setState((prevState, props) => ({count: this.state.count + 1})) // 3
  this.setState({name: "xiaohesong"}) // 4
}

上面的这段代码里的这四个会被塞进队列里进行批量操作.批量操作?

Object.assign(state, {count: this.state.count + 1}, {count: this.state.count + 1}, ..., {name: "xiaohesong"})

如果把上面的代码换成异步的呢?

componentDidMount(){
    setTimeout(() => {
        this.setState(count => this.state.count + 1)
        this.setState(count => this.state.count + 1)
    })
}

可以发现,如果改成这样,也会触发 re-render. 可是这是为啥setTimeout里的两次this.state.count会成功,而不是像上面一样,浅合并成一个呢?
这个还得继续探索.

总结

  1. setState操作,默认情况下是每次调用, 都会re-render一次,除非你手动shouldComponentUpdatefalse.
    react为了减少rerender的次数,会进行一个浅合并.将多次re-render减少到一次re-render.

  2. setState之后,无法立即获取到this.state的值,是因为在setState的时候,他只会把操作放到队列里.

参考链接

  1. anhuiliujun react Api 之 setState 与 forceUpdate
  2. setState() Gate

本站文章均为原创内容,如需转载请注明出处,谢谢。

2 条回复
喜欢
统计信息
    学员: 29063
    视频数量: 1973
    文章数量: 489

© 汕尾市求知科技有限公司 | Rails365 Gitlab | Qiuzhi99 Gitlab | 知乎 | b 站 | 搜索

粤公网安备 44152102000088号粤公网安备 44152102000088号 | 粤ICP备19038915号

Top