React setState() 详情

为什么使用 setState()setState() 会对一个组件的 state 对象安排一次更新。当 state 改变了,该组件就会重新渲染。开发中我们不能直接通过修改 state 当中的值来让界面发生更新,因为修改了 state 后希望的是 React 根据最新的 state 值来进行更新界面,但是这种方式 React 并不知道数据发生了变化,所以必须通过 setState() 来告诉 React 数据已经发生了变化需要更新界面。

一、setState 可能是异步更新

class App extends Component {
  constructor() {
    super();
    this.state = {
      number: 0
    }
  }
  render() {
    return (
      <div>
        <h2>{this.state.number}</h2>
        <button onClick={e => this.addText()}>+1</button>
      </div>
    )
  }
  addText() {
    this.setState({
      number: this.state.number + 1
    });
    console.log(this.state.number);   // 0
  }
}

当调用 this.setState({ number: this.state.number + 1 }) 后所打印得到的值依旧为 0。
获取异步更新后的数据:

class App extends Component {
  constructor() {
    super();
    this.state = {
      number: 0
    }
  }
  render() {
    return (
      <div>
        <h2>{this.state.number}</h2>
        <button onClick={e => this.addText()}>+1</button>
      </div>
    )
  }
  // 方式二:通过声明周期函数获取异步更新的值
  componentDidUpdate() {
    console.log(this.state.number); // 1
  }
  addText() {
    this.setState({
      number: this.state.number + 1
    }, () => {  // 方式一:通过 setState 的回调函数获取异步更新的值
      console.log(this.state.number);   // 1
    });
  }
}

二、setState 可能是同步更新

  • 当 setState() 方法在 setTimeout() 中执行:
class App extends Component {
  constructor() {
    super();
    this.state = {
      number: 0
    }
  }
  render() {
    return (
      <div>
        <h2>{this.state.number}</h2>
        <button onClick={e => this.addText()}>+1</button>
      </div>
    )
  }
  addText() {
    setTimeout(() => {
      this.setState({
        number: this.state.number + 1
      });
      console.log(this.state.number); // 1
    }, 0);
  }
}
  • 当 setState() 方法在原生 DOM 事件中执行:
class App extends Component {
  constructor() {
    super();
    this.state = {
      number: 0
    }
  }
  componentDidMount() {
    // 原生点击事件
    const btnEl = document.getElementById('btn');
    btnEl.addEventListener('click', () => {
      this.setState({
        number: this.state.number + 1
      });
      console.log(this.state.number); // 1
    })
  }
  render() {
    return (
      <div>
        <h2>{this.state.number}</h2>
        <button id='btn'>+1</button>
      </div>
    )
  }
}

一般情况下,setState() 方法在组件生命周期或 React 合成事件中是异步更新的;在 setTimeout() 或者原生 DOM 事件中是同步的。

三、setState 数据的合并

// this.state 当中有两个属性
constructor() {
    super();
    this.state = {
      number: 0,
      name: 'zhangsan'
    }
}
/* --------------- */
// 更新 state
this.setState({
     number: 10
});

constructor 中的 this.state 有多个属性时,调用 this.setState() 方法更新其中一条 number 属性后,不会将之前的 name 属性覆盖,而是单独修改 number 属性,等同于:
Object.assign({}, this.state, { number: 10 })

四、setState 本身的合并

class App extends Component {
  constructor() {
    super();
    this.state = {
      number: 0
    }
  }
  render() {
    return (
      <div>
        <h2>{this.state.number}</h2>
        <button onClick={e => this.addText()}>+1</button>
      </div>
    )
  }

  addText() {
    // setState 本身被合并
    // this.setState({
    //   number: this.state.number + 1
    // });
    // this.setState({
    //   number: this.state.number + 1
    // });
    // this.setState({
    //   number: this.state.number + 1
    // });
    /* 最终结果还是 1 */

    // setState 合并时进行累加
    this.setState((prevState, props) => {
      return {
        number: prevState.number + 1
      }
    })
    this.setState((prevState, props) => {
      return {
        number: prevState.number + 1
      }
    })
    this.setState((prevState, props) => {
      return {
        number: prevState.number + 1
      }
    })
    /* 最终结果为 3 */
  }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容