React中setState()更新状态的两种写法及相关问题

1、setState(updater, [callback])------函数式的setState

updater是一个返回stateChange对象的函数(如下代码所示),它接收的stateprops都保证为最新updater的返回值会与state进行浅合并。

stateChange为状态改变对象(该对象可以体现出状态的更改)。callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render()调用后)才被调用。

(state, props) => stateChange
2、setState(stateChange, [callback])------对象式的setState

stateChange为状态改变对象(该对象可以体现出状态的更改),callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render()调用后)才被调用。

总结:
1、对象式的setState是函数式的setState的简写方式(语法糖)
2、使用原则:

  • 如果新状态不依赖于原状态 => 使用对象方式
  • 如果新状态依赖于原状态 => 使用函数方式
  • 如果需要在setState()执行后获取最新的状态数据, 要在第二个callback函数中读取
3、关于setState()更新状态的同步异步问题:

总的来说,可能是异步也可能是同步的。

  • 在react控制的回调函数(生命周期回调、react事件监听回调等)中,它更新状态的操作就是异步的,异步更新后的状态数据在setState()callback回调函数中;

  • 在非react控制的回调函数(定时器、原生事件监听、promise回调等)中,它更新状态的操作就是同步的。

  • 函数式的setState如果多次调用:由于函数式的setState内的updater函数所接收的stateprops都保证为最新,故它会更新多次状态,但是只调用一次render()更新界面 ------ 状态更新没有合并,但界面更新合并了

  • 对象式的setState如果多次调用:只合并更新一次状态,只调用一次render()更新界面 ------ 状态更新和界面更新都合并了

class Demo extends React.Component{
  state = {
    count: 0
  }
  componentDidMount(){
    this.setState({count: this.state.count + 1}) // 3.1 -> count = 0 + 1
    this.setState({count: this.state.count + 1}) // 3.2 -> count = 0 + 1
    console.log(this.state.count) // 2 -> 0
    
    this.setState(state => ({count: state.count + 1})) // 3.3 -> count = 1 + 1
    this.setState(state => ({count: state.count + 1})) // 3.4 -> count = 2 + 1
    console.log(this.state.count) // 3 -> 0
    
    setTimeout(() => {
      this.setState({count: this.state.count + 1}) // 8.1 -> count = 5 + 1
    	console.log('timeout', this.state.count) // 10 -> 6
      
      this.setState({count: this.state.count + 1}) // 10.1 -> count = 6 + 1
    	console.log('timeout', this.state.count) // 12 -> 7
    }, 0)
    
    Promise.resolve().then(value => { //Promise先于setTimeout执行
      this.setState({count: this.state.count + 1}) //调用setState后马上去render渲染,故4.1 -> count = 3 + 1
      console.log('Promise', this.state.count) // 6 -> 4
      
      this.setState({count: this.state.count + 1}) // 6.1 -> count = 4 + 1
    	console.log('Promise', this.state.count) // 8 -> 5
    })
  }
  render(){
    const count = this.state.count
    console.log('render', count) // 1 -> 0  // 4 -> 3  // 5 -> 4  // 7 -> 5  // 9 -> 6  // 11 -> 7
    return (
    	<div>
      	<p>{count}</p>
      </div>
    )
  }
}
//render 0
//0
//0
//render 3
//render 4
//Promise 4
//render 5
//Promise 5
//render 6
//timeout 6
//render 7
//timeout 7

你可能感兴趣的:(react.js,javascript,前端)