对于 React 中 setState() 的理解

一、setState() 的使用
  1. setState() 更新状态的两种写法,如下所示:
  • setState(updater, [callback])updater 为返回 stateChange 对象的函数: (state, props) => stateChange,接收的 stateprops 被保证为最新的
  • setState(stateChange, [callback])stateChange 为对象,callback 是可选的回调函数,在状态更新且界面更新后才执行
  1. 对于 setState() 写法的总结,如下所示:
  • 对象方式是函数方式的简写方式
  • 如果新状态不依赖于原状态,那么就使用对象方式
  • 如果新状态依赖于原状态,那么就使用函数方式
  • 如果需要在 setState() 后获取最新的状态数据,在第二个 callback 函数中读取
  1. 对于 setState() 的简单应用,代码如下所示:
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>setState()</title>
</head>
<body>

<div id="example"></div>

<script type="text/javascript" src="./js/react.development.js"></script>
<script type="text/javascript" src="./js/react-dom.development.js"></script>
<script type="text/javascript" src="./js/babel.min.js"></script>

<script type="text/babel">

  class A extends React.Component {

    state = {
      count: 1
    }

    test1 = () => {
      this.setState(state => ({count: state.count + 1}))
      console.log('test1 setState()之后', this.state.count)
    }

    test2 = () => {
      /*const count = this.state.count + 1
      this.setState({
        count
      })*/
      this.setState({
        count: 3
      })
      console.log('test2 setState()之后', this.state.count)
    }

    test3 = () => {
      this.setState(state => ({count: state.count + 1}), () => { // 在状态更新且界面更新之后回调
        console.log('test3 setState callback()', this.state.count)
      })
    }

    render() {
      console.log('A render()')
      return (
        <div>
          <h1>A组件: {this.state.count}</h1>
          <button onClick={this.test1}>A 测试1</button>&nbsp;&nbsp;
          <button onClick={this.test2}>A 测试2</button>&nbsp;&nbsp;
          <button onClick={this.test3}>A 测试3</button>&nbsp;&nbsp;
        </div>
      )
    }
  }

  ReactDOM.render(<A/>, document.getElementById('example'))
</script>
</body>
</html>

二、setState() 更新状态的同步与异步
  1. react 中,执行 setState() 的位置,如下所示:
  • react 控制的回调函数中,有生命周期勾子函数、react 事件监听回调等等
  • react 控制的异步回调函数中,有定时器回调、原生事件监听回调、promise 回调等等
  1. react 中,setState() 的同步与异步,如下所示:
  • react 相关回调中是异步的
  • 其它异步回调中是同步的
  1. 对于异步的 setState(),在多次调用时进行处理,如下所示:
  • setState({}): 合并更新一次状态,只调用一次 render() 更新界面,状态更新和界面更新都合并了
  • setState(fn): 更新多次状态, 但只调用一次 render() 更新界面 ,状态更新没有合并, 但界面更新合并了
  1. 对于异步的 setState(),得到异步更新后的状态数据,可以在 setState()callback 回调函数中

  2. 对于 setState() 更新状态的异步与同步的应用,代码如下所示:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>setState()</title>
</head>
<body>

<div id="example"></div>

<script type="text/javascript" src="./js/react.development.js"></script>
<script type="text/javascript" src="./js/react-dom.development.js"></script>
<script type="text/javascript" src="./js/babel.min.js"></script>

<script type="text/babel">

  
  class StateTest extends React.Component {

    state = {
      count: 0,
    }

    /*
     react事件监听回调中, setState()是异步更新状态
     */
    update1 = () => {
      console.log('update1 setState()之前', this.state.count)
      this.setState(state => ({count: state.count + 1}))
      console.log('update1 setState()之后', this.state.count)
    }

    /*
     react生命周期勾子中, setState()是异步更新状态
     */
    componentDidMount () {
      console.log('componentDidMount setState()之前', this.state.count)
      this.setState(state => ({count: state.count + 1}))
      console.log('componentDidMount setState()之后', this.state.count)
    }

    /*
    定时器回调 / 原生事件监听回调 / promise回调 /...
     */
    update2 = () => {
      setTimeout(() => {
        console.log('setTimeout setState()之前', this.state.count)
        this.setState(state => ({count: state.count + 1}))
        console.log('setTimeout setState()之后', this.state.count)
      })
    }
    update3 = () => {
      const h2 = this.refs.count
      h2.onclick = () => {
        console.log('onclick setState()之前', this.state.count)
        this.setState(state => ({count: state.count + 1}))
        console.log('onclick setState()之后', this.state.count)
      }
    }
    update4 = () => {
      Promise.resolve().then(value => {
        console.log('Promise setState()之前', this.state.count)
        this.setState(state => ({count: state.count + 1}))
        console.log('Promise setState()之后', this.state.count)
      })
    }


    update5 = () => {
      console.log('onclick setState()之前', this.state.count)
      this.setState(state => ({count: state.count + 1}))
      console.log('onclick setState()之后', this.state.count)
      console.log('onclick setState()之前2', this.state.count)
      this.setState(state => ({count: state.count + 1}))
      console.log('onclick setState()之后2', this.state.count)
    }

    update6 = () => {
      console.log('onclick setState()之前', this.state.count)
      this.setState({count: this.state.count + 1})
      console.log('onclick setState()之后', this.state.count)
      console.log('onclick setState()之前2', this.state.count)
      this.setState({count: this.state.count + 1})
      console.log('onclick setState()之后2', this.state.count)
    }

    update7 = () => {
      console.log('onclick setState()之前', this.state.count)
      this.setState({count: this.state.count + 1})
      console.log('onclick setState()之后', this.state.count)

      console.log('onclick setState()之前2', this.state.count)
      this.setState(state => ({count: state.count + 1}))
      console.log('onclick setState()之后2', this.state.count)
    }


    render() {
      const {count} = this.state
      console.log('render()', count)
      return (
        <div>
          <h2 ref='count'>{count}</h2>
          <button onClick={this.update1}>更新1</button> ---
          <button onClick={this.update2}>更新2</button> &nbsp;
          <button onClick={this.update3}>更新3</button> &nbsp;
          <button onClick={this.update4}>更新4</button> ---
          <button onClick={this.update5}>更新5</button> &nbsp;
          <button onClick={this.update6}>更新6</button> &nbsp;
          <button onClick={this.update7}>更新7</button> &nbsp;
        </div>
      )
    }
  }

  ReactDOM.render(<StateTest/>, document.getElementById('example')) // 渲染组件标签, 内部会调用组件标签对象的render()虚拟DOM

</script>
</body>
</html>

三、setState() 的面试题
  1. 对于 setState() 的面试题,代码如下所示:
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>setState()</title>
</head>
<body>

<div id="example"></div>

<script type="text/javascript" src="./js/react.development.js"></script>
<script type="text/javascript" src="./js/react-dom.development.js"></script>
<script type="text/javascript" src="./js/babel.min.js"></script>

<script type="text/babel">
  class StateTest extends React.Component {

    state = {
      count: 0,
    }

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

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

      setTimeout(() => {
        this.setState({count: this.state.count + 1})
        console.log('timeout', this.state.count) // 10 ==> 6

        this.setState({count: this.state.count + 1})
        console.log('timeout', this.state.count) // 12 ==> 7
      }, 0)

      Promise.resolve().then(value => {
        this.setState({count: this.state.count + 1})
        console.log('promise', this.state.count)  // 6 ==>4

        this.setState({count: this.state.count + 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>
      )
    }
  }

  ReactDOM.render(<StateTest/>, document.getElementById('example'))

</script>
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值