# 1. setState的用法概括

setState的3种用法

用法1:setState的第二参数 回调函数,会等到setState状态异步更新完毕且真实dom被渲染完毕,此时可以拿到最新的状态值

用法2:三个同key值的操作会被合并处理,只取最后一个的setState,最后一个覆盖之前的

用法3:setState的第一个参数是回调函数,该回调函数有一个参数prevstate是之前的状态,多个setState会被加到一个队列中,前一个更新到dom中,才会执行下一个,且同步完成

用法4:在setTimout或者原生事件中,setState是同步的

# 2. setState的3种用法

import React from 'react'

class App extends React. Component{
  state = {

    count: 0

  }

  render() {

    return <div>
      {this.state.count}
      <button onClick = {this.handleCount1}>click-1</button>
      <button onClick = {this.handleCount2}>click-2</button>
      <button onClick = {this.handleCount3}>click-3</button>
    </div>

  }
}
export default App

# 2-1 用法1(第二个参数 回调函数取得最新的状态值)

handleCount1 = () => {
  // setState 用法1
  this. setState({

    count: this.state.count + 1

  }, () => {

    console.log(this.state.count) // 此时访问的是真实的dom,dom已经渲染完毕

  })
}

setState的第二参数 回调函数,会等到setState状态异步更新完毕且真实dom被渲染完毕,此时可以拿到最新的状态值

# 2-2 用法2(三个同key值的操作会被合并处理)

handleCount2 = () => {
  this. setState({

    count: this.state.count + 1

  })
  
  this. setState({

    count: this.state.count + 1

  })
  
  this. setState({

    count: this.state.count + 5

  })
  console. log(this. state. count)  // 5
}

三个同key值的操作会被合并处理,只取最后一个的setState,最后一个覆盖之前的

# 2-3 用法3(加入队列,后一个等前一个限制性完成,同步)

handleCount3 = () => {
  this. setState((prevstate) => ({

    count: prevstate.count +1 

  }))
  this. setState((prevstate) => ({

    count: prevstate.count +1 

  }))
  this. setState((prevstate) => ({

    count: prevstate.count +1 

  }))
  console. log(this. state. count)  // 3
}

setState的第一个参数是回调函数,该回调函数有一个参数prevstate是之前的状态,多个setState会被加到一个队列中,前一个更新到dom中,才会执行下一个,且同步完成

细节补充

function test() {
  return {

    name: "kerwin"

  }
}

错误写法 {} 里包含的应该是函数体,不符合js语法
var test2 = () => {
  name: "kerwin"
}

正确写法
var test2 = () => ({
  name: "kerwin"
})

# 2-4 用法5(在setTimeout事件中,同步)

handleCount4 = () => {
  this. setState({

    count: this.state.count + 1

  })
  console. log(this. state. count)  // 0
  setTimeout(_ => {

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

  }, 2000)
  setTimeout(_ => {

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

  }, 2000)
}

setTimout或者原生事件中,setState是同步的

# 3. setState的后发生了什么?setState为什么默认是异步?setState什么时候是同步?

# 3-1 setState的后发生了什么?

  • setState之后,React会将传入的参数对象和当前的状态合并,重新构建React元素树并且重新渲染整个UI界面。

  • React会生成新的虚拟dom,与老的dom节点进行对比diff算法对比,以最小的代价更新真实dom,重新渲染。

  • 在diff算法比对中,React能够精确的知道哪些位置发生了变化,以及如何改变,这就保证了按需更新,而不是全部重新渲染

# 3-2 setState为什么默认是异步?

  • 加入所有的setState都是同步的,意味着每执行一次setState时,都重新虚拟dom diff算法对比真实dom,这对性能来说是极为不好的。

  • 如果是异步,则可以把一个同步代码中的多个setState合并称一次组件更新

# 3-3 setState什么时候是同步?

setTimout或者原生事件中,setState是同步的

# 4. 多次调用setState 会不会对性能产生影响?

不会,三个同key值的操作,会被合并处理,以最后一个为主,最后一个会覆盖之前的