Bootstrap

1分钟带你get React setState 面试要点

前言: 对于React的初学者来说,setState这个API是再亲切不过了,但你真的了解它了吗?面试时工作是,你能讲清楚他吗?

我们来先看几道题目吧?

  • Q1:

...
state = {
	count: 0
}
componentDidMount() {
  this.setState({count: this.state.count + 1})
  console.log(this.state.count)
  
  this.setState({count: this.state.count + 1})
  console.log(this.state.count)
  
  this.setState({count: this.state.count + 1})
  console.log(this.state.count)
  
  setTimeout(() => {
    console.log(this.state.count)
    this.setState({count: this.state.count + 1})
    console.log(this.state.count)
    
    this.setState({count: this.state.count + 1})
    console.log(this.state.count)
  }, 0)
  
  console.log(this.state.count, 'end')
}
...
  • Q2:

...
state = {
	count: 0
}
componentDidMount() {
	this.setState(state => ({count: state.count + 1}), () => {console.log(this.state.count)})
  console.log(this.state.count)
  
  this.setState(state => ({count: state.count + 1}), () => {console.log(this.state.count)})
  console.log(this.state.count)
  
  this.setState(state => ({count: state.count + 1}), () => {console.log(this.state.count)})
  console.log(this.state.count, 'end')
}
...

如果你能很清晰的回答出来,那么恭喜你

setState 是同步还是异步?

我们先来看Q1的答案

console.log ---- down ---
0
0
0
0 'end'
3
4

从表面上来看,在同步代码块中他是异步更新的,在异步代码块中他是同步的更新的,但是我想说的是能够由React控制的它就是异步更新,不能由React控制的他是同步更新!

  • React控制的

  • React的生命周期

  • React注册的事件

  • React不能控制的

  • setTimeout、setInterval

  • 自定义注册的DOM事件

要搞清楚这些,要需要理解2个概念bathUpdate,Transacation

batchUpdate批量更新

一句话搞定就是,这个有点机制像函数防抖,React会尽量的减少不必要的刷新,能一起更新的就一起更新了。

Transacation事务机制

一句话搞定就是,这个就是实现batchUpdate的模型,他看起来就像requestAnimationFrame;这也是React实现异步渲染的一个重要基石,每当React获取控制权的时候就会执行batchUpdate,当React失去控制权的时候,setState就是同步代码一样。

setState 是否合并操作?

再来看看Q2的答案

console.log ---- down ---
0
0
0 'end'
3
3
3

结合Q1的例子来看,当setState传入的第一个参数是object数据类型那么它就会合并,传入的是function数据类型,那么它就不会合并;可以想象如果传入的是oject数据类型,它大可以通过Object.assgin这样的API将其合并,如果是function数据类型化,依次执行

小结

本文主要描述了React setState 的两个现象,操作是否合并和是否异步更新。

  • setState 操作合并

  • 当第一个传入的参数是object数据类型它就会合并,类型调用了Object.assgin

  • 当参数类型是function数据类型时,不会合并

  • setState 是否异步

  • React获得控制权的时候,它就是异步执行

  • React什么周期内

  • React注册的事件内

  • 当React丧失控制权的时候,它就是同步执行

  • setTimeout、Promise 等异步函数

  • 自定义注册DOM事件等

小测验,看你都掌握了吗?

赘述了这么多,下面的code对你来说一定是小菜一碟了吧?

...
state = {
 	count: 0 
}
componentDidMount() {
   this.setState(state => ({count: state.count + 1}), () => {console.log(this.state.count)})
    console.log(this.state.count)
    
    this.setState(state => ({count: state.count + 1}), () => {console.log(this.state.count)})
    console.log(this.state.count)
    
    this.setState(state => ({count: state.count + 1}), () => {console.log(this.state.count)})
    console.log(this.state.count, 'end')
  }

  handleCount = () => {
    this.setState({ count: this.state.count + 1 });
    console.log(this.state.count);

    this.setState({ count: this.state.count + 1 });
    console.log(this.state.count);

    this.setState({ count: this.state.count + 1 });
    console.log(this.state.count);

    Promise.resolve().then(() => {
      console.log(this.state.count);
      this.setState({ count: this.state.count + 1 });
      console.log(this.state.count);

      this.setState({ count: this.state.count + 1 });
      console.log(this.state.count);
    })

    console.log(this.state.count, 'end1');

    this.setState(state => ({count: state.count + 1}), () => {console.log(this.state.count, '1')})
    console.log(this.state.count)
    
    this.setState(state => ({count: state.count + 1}), () => {console.log(this.state.count, '2')})
    console.log(this.state.count)
    
    this.setState(state => ({count: state.count + 1}), () => {console.log(this.state.count, '3')})
    console.log(this.state.count, 'end2') 
}

参考: