React(7)异步的数据更改(setState 是异步行为)

x33g5p2x  于2022-03-06 转载在 其他  
字(2.1k)|赞(0)|评价(0)|浏览(559)

与Vue不同,React的设置变量是异步的。

13、setState 是异步行为

setState()

这是一个异步操作,如:

  1. class HelloWord extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {
  5. count: 0
  6. }
  7. this.clickCountAsync = this.clickCountAsync.bind(this)
  8. }
  9. // 渲染函数,this 指向实例本身
  10. render() {
  11. return <div>
  12. <button onClick={this.clickCountAsync}>异步增加count</button>
  13. </div>
  14. }
  15. clickCountAsync() {
  16. console.log('【异步】setState之前,count的值:', this.state.count)
  17. this.setState({
  18. count: this.state.count + 1
  19. })
  20. console.log('【异步】setState之后,count的值:', this.state.count)
  21. }
  22. }

会发现,两个 log 语句,输出的结果的值,都是一样的。

原因是 React 会合并多个 setState,然后统一更新;

那么如何获取更新后的数据,答案是通过回调函数;

说明见注释

  1. class HelloWord extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {
  5. count: 0,
  6. anotherCount: 0
  7. }
  8. this.clickCountAsync = this.clickCountAsync.bind(this)
  9. this.clickCountSync = this.clickCountSync.bind(this)
  10. }
  11. // 渲染函数,this 指向实例本身
  12. render() {
  13. return <div>
  14. <button onClick={this.clickCountAsync}>异步增加count</button>
  15. <br/>
  16. <button onClick={this.clickCountSync}>增加count,并同步更新计数器二的值等于异步增加后的count</button>
  17. <br/>
  18. 计数器二:{this.state.anotherCount}
  19. </div>
  20. }
  21. clickCountAsync() {
  22. console.log('【异步】setState之前,count的值:', this.state.count)
  23. this.setState({
  24. count: this.state.count + 1
  25. })
  26. console.log('【异步】setState之后,count的值:', this.state.count)
  27. }
  28. clickCountSync() {
  29. // 通过setState 更新 state.count 的值
  30. this.clickCountAsync()
  31. // 1、这里是更新前的值
  32. console.log('【同步】setState之前,count的值:', this.state.count)
  33. this.setState((prevState, props) => {
  34. // 3、这里的回调函数,是更新后执行(即
  35. console.log(prevState, props)
  36. // 返回值就像设置 setState 的参数一样
  37. return {
  38. anotherCount: prevState.count
  39. }
  40. })
  41. // 2、这里也是更新前的值
  42. console.log('【同步】setState之后,count的值:', this.state.count)
  43. }
  44. }

当然,这又出现一个问题,那就是假如我调用一个方法,分别修改了 A 变量,然后又调用某个方法需要修改 B 变量,并且 B 变量依赖于 A 变量修改后的值(这就是以上场景);

可是假如我又需要调用第三个方法修改 C 变量,并且 C 的值依赖于 B 修改后的值。那么这就有问题了。

原因是:

  1. React 里并不存在类似 Vue 的 computed/watch 这样的计算属性。如果需要实现,那么可能需要引入额外的库(watch.js/Rx.js/mobx);
  2. setState 本身是异步的,并且回调函数获取变更后的值,也是异步的。因此在场景复杂的情况下,你很难判断哪一个 setState 的回调函数,会优先执行;

解决办法:

  1. 一个是引入额外的库,仿 Vue.js;
  2. 考虑使用生命周期函数 componentWillUpdate(nextProps, nextState),将依赖的变量的修改逻辑,添加到这个函数里,如下面代码,可以解决部分场景的问题;
  1. componentWillUpdate(nextProps, nextState) {
  2. nextState.anotherCount *= 2
  3. console.log(nextProps, nextState)
  4. }

相关文章