setState同步OR异步

setState()更新状态的两种写法

  1. setState(updater,[callback])react

    updater 为返回stateChange的函数的对象,(state,props) => stateChange面试

    接收的state和props被保证为最新的promise

    函数方式:babel

    1、若是新状态依赖于原状态
    this.setState((state,props) => ({
       count: state.count+1 
    }),()=>{
        // callback
    })
    复制代码
  2. setState(stateChange,[callback])dom

stateChange为对象异步

callback是可选的回调函数,在状态更新且界面更新后才执行函数

对象方式:测试

1、新状态不依赖于原状态 ==>使用对象方式
this.setState({count:this.state.count+1},()=>{
    // callback
})
复制代码

案例

<body>
  <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
  <div id="root"></div>
  <script type="text/babel">
      
    class App extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          count:0
        }
      }
      test1 = ()=> {
        // 若是新状态依赖于原状态,使用函数方式
        this.setState((state,props)=> ({
          count: state.count+1
        }))
        console.log('test1以后获取count的值:',this.state.count); // 0
      }
      test2 = ()=> {
        // 新状态不依赖于原状态 ==>使用对象方式
        const count = this.state.count + 1;
        this.setState({count});
        console.log('test2以后获取count的值:',this.state.count);
      }
      test3 = ()=> {
        this.setState(state =>({
          count: state.count + 1
        }),()=>{
          console.log('test3-----setState回调函数中count的值:',this.state.count);
        })
      }
      render() {
        return (
          <div>
            <h1>A组件:{this.state.count}</h1>
            <button onClick={this.test1}>测试1</button><br />
            <button onClick={this.test2}>测试2</button><br />  
            <button onClick={this.test3}>测试3</button><br />                
          </div>
        )
      }
    }
    ReactDOM.render(<App />,document.getElementById('root'));
  </script>

</body>
复制代码

setState的同步与异步

setState()内部是利用的 “事务” 实现异步更新状态ui

同步

定时器,DOM事件监听回调,Promisethis

异步

在react控制的回调函数中:生命周期钩子 、 react事件监听的回调

异步的setState() 屡次调用,如何处理?

注意:异步状况

  • setState({}): 合并更新一次状态,只调用一次render()更新界面 --- 状态更新和界面更新都合并了
  • setState(fn): 更新屡次状态,但只调用一次render更新界面, ----状态更新没有合并但界面更新合并了
  • 先执行setState({}) 对象方式再执行**setState(fn)**函数方式,状态更新没有合并,但界面更新合并了

获得异步更新后的状态数据

在setState()的callback回调函数中

案例

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
  <div id="root"></div>
  <script type="text/babel">
    
    class App extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          count:0
        }
      }
      /** * react事件监听相关的回调中:- setState()是异步更新状态的 */ 
      test1 = ()=> {
        console.log('setSate回调函数以前---react事件监听回调',this.state.count);        
        this.setState(state=>({
          count:state.count+1
        }))  
        console.log('setSate回调函数以后---react事件监听回调',this.state.count);
      }
      /** * react生命周期钩子中:- setState()是异步更新状态的 */ 
      componentDidMount() {
        console.log('setSate回调函数以前---生命周期钩子',this.state.count);        
        this.setState(state=>({
          count:state.count+1
        }))  
        console.log('setSate回调函数以后--生命周期钩子',this.state.count); 
      }
      // 同步 (定时器,DOM事件监听回调,Promise)

      test2 = ()=> {
        setTimeout(() => {
          console.log('setSate回调函数以前---定时器',this.state.count);        
          this.setState(state=>({
            count:state.count+1
          }))  
          console.log('setSate回调函数以后---定时器',this.state.count); 
        }, 0);
      }
      test4 = () => {
        const btn4 = this.refs.btn4;
        btn4.onclick = ()=> {
          console.log('setSate回调函数以前---原生DOM',this.state.count);        
          this.setState(state=>({
            count:state.count+1
          }))  
          console.log('setSate回调函数以后---原生DOM',this.state.count); 
        }
      }
      test3 = ()=> {
        Promise.resolve().then(res => {
          console.log('setSate回调函数以前---Promise',this.state.count);        
          this.setState(state=>({
            count:state.count+1
          }))  
          console.log('setSate回调函数以后---Promise',this.state.count); 
        })
      }
      test5 = ()=> {
        console.log('setState 函数方式 - 1 --调用前',this.state.count);
        this.setState(state => ({
          count: state.count+1
        }))
        console.log('setState 函数方式 - 1 --调用后',this.state.count);
        this.setState(state => ({
          count: state.count+1
        }))
        console.log('setState 函数方式 - 2 --调用后',this.state.count);
      }
      test6 = ()=> {
        console.log('setState 对象方式 - 1 --调用前',this.state.count);
        this.setState({count:this.state.count+1});
        console.log('setState 对象方式 - 1 --调用后',this.state.count);
        this.setState({count:this.state.count+1});
        console.log('setState 对象方式 - 2 --调用后',this.state.count);
      }
      test7 = () => {
        console.log('setState 对象方式 - 1 --调用前',this.state.count);
        this.setState({count:this.state.count+1});
        console.log('setState 对象方式 - 1 --调用后',this.state.count);
        this.setState(state => ({
          count: state+1
        }));
        console.log('setState 函数方式 - 1 --调用后',this.state.count);
      }

      render() {
        return (
          <div> <h1>A组件:{this.state.count}</h1> <button onClick={this.test1}>测试1</button><br /> <button onClick={this.test2}>测试2</button><br /> <button onClick={this.test3}>Promise</button><br /> <button ref="btn4" onClick={this.test4}>原生DOM</button><br /> <button onClick={this.test5}>setState屡次调用---函数方式</button><br /> <button onClick={this.test6}>setState屡次调用---对象方式</button><br /> <button onClick={this.test7}>setState屡次调用---对象方式和函数方式</button><br /> </div>
        )
      }
    }
    ReactDOM.render(<App />,document.getElementById('root')); </script>
复制代码

setState()常见的面试题

若是上面讲解的内容都能理解的,下面的内容很容易的。🙂

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
  <div id="root"></div>
  <script type="text/babel">
    class App extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          count:0
        }
      }
      /** * Promise和定时器相比,promise会先执行 * setState()执行一次,致使数据发生变化,就会触发render的更新 */ 

      componentDidMount() {
        this.setState({count:this.state.count+1});
        this.setState({count:this.state.count+1});
        console.log('1----',this.state.count); // 2 --> 0(上面两个会被合并成一个)

        this.setState(state => ({
          count: state.count+1
        }))
        this.setState(state => ({
          count: state.count+1
        }))
        console.log('2-----',this.state.count); // 3 --> 0 (第四次执行,输出结果为3)
        
        setTimeout(() => {
          this.setState({count:this.state.count+1});
          console.log('timeout-1',this.state.count); // 8 ---> 6
          this.setState({count:this.state.count+1});
          console.log('timeout-2',this.state.count); // 10 ---> 7
        }, 0);

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

      }
     
      render() {
        const count = this.state.count;
        console.log('render',count); // 1 --- 0 , 4 ---> 3, 6 ---> 4 , 9 ---> 6,11 --> 7
        return (
          <div> <h1>A组件:{this.state.count}</h1> </div>
        )
      }
    }
    ReactDOM.render(<App />,document.getElementById('root')); </script>
复制代码
相关文章
相关标签/搜索