setState异步真的只是为了性能吗?

简介: 我们在 React 使用 setState时知道,它并不总是异步更新,也可能是同步更新,大家也知道setState使用异步是为累积更新、批量处理、减少调用次数来提升性能,但是大家有没有想过setState的异步更新真的单单是为了性能吗?

前言


我们在 React 使用 setState时知道,它并不总是异步更新,也可能是同步更新,大家也知道setState使用异步是为累积更新、批量处理、减少调用次数来提升性能,但是大家有没有想过setState的异步更新真的单单是为了性能吗?

网络异常,图片无法展示
|


setState API


setState(updater, [callback])
updater
(state, props) => stateChange


updater 函数中接收的 state 和 props 都保证为最新。updater 的返回值会与 state 进行浅合并。


callback

setState() 的第二个参数为可选的回调函数,它将在 setState 完成合并并重新渲染组件后执行。通常,我们建议使用 componentDidUpdate() 来代替此方式。


异步


setState将对组件state的更改排入队列,并通知React需要使用更新后的state重新渲染组件及其子组件。为了更好的性能,setState并不是立即进行更新,而是使用批量推迟更新。


看几个异步的例子,这些都是经常出现在面试中的代码例子(源码测试

class Test extends Component {
  state = {
    count: 0
  };
  componentDidMount() {
    this.setState({
        count: 1
      }, () => {
        console.log(this.state.count); //1
      }
    );
    console.log(this.state.count); // 0
  }
  render() {}
}
class Test extends Component {
  state = {
    count: 0
  };
  componentDidMount() {
    this.setState(
      {
        count: this.state.count + 1
      },
      () => {
        console.log(this.state.count); // 1
      }
    );
    this.setState(
      {
        count: this.state.count + 1 // 这里的count还是0,并不会拿到更新后的count
      },
      () => {
        console.log(this.state.count); // 1 
      }
    );
  }
  render() {}
}
class Test extends React.Component {
  state = {
    count: 0
  };
  componentDidMount() {
    this.setState(
      (preState) => {
        console.log(preState.count); // 0
        return {
          count: preState.count + 1
        };
      },
      () => {
        console.log(this.state.count); // 2
      }
    );
    this.setState(
      (preState) => {
        console.log(preState.count); // 1
        return {
          count: preState.count + 1
        };
      },
      () => {
        console.log(this.state.count); // 2
      }
    );
  }
  render() {
    return <div>1</div>;
  }
}码


当调用setState函数时,就会把当前的操作放入到队列中,React 根据内容合并state数据,完成之后在逐一执行回调,根据结果去更新需求DOM,触发渲染。这里采用的是异步的方法,根据说法是异步是为了累积更新,批量处理,减少渲染次数,提升性能。


难道同步就不能累积更新、批量处理了吗


这里其实我们换一个角度来想想,难道同步就不能累积更新、批量处理了吗?难道同步就不能减少渲染次数,提升性了吗?

网络异常,图片无法展示
|


这个问题其实不止我有疑问,很早之前有大佬就已经在Issues上有提出这个问题:

网络异常,图片无法展示
|


当然在这个 Issues 下面 gaearon 大佬回复了这个问题:


网络异常,图片无法展示
|

网络异常,图片无法展示
|

网络异常,图片无法展示
|


回答的比较长,大体总结了两个方面:


1. 保持一致性


如果改为同步更新的方法,虽然setState是同步的,但是props不是。


2. 为后续的架构升级启用并发更新


为了完成一部的渲染,React会在触发 setState 的时候更新数据来源分配不同的优先级。这些数据的来源有:事件回调句柄、动画效果等,在根据优先级并发处理,提升渲染性能。



目录
相关文章
|
6月前
|
前端开发 JavaScript
React 中 setState 什么时候是同步的,什么时候是异步的
React 中 setState 什么时候是同步的,什么时候是异步的
62 0
|
8月前
|
前端开发 JavaScript
react的setState是异步还是同步
react的setState是异步还是同步
|
5天前
|
JavaScript 前端开发
揭秘 `nextTick`:解决异步回调的利器(上)
揭秘 `nextTick`:解决异步回调的利器(上)
揭秘 `nextTick`:解决异步回调的利器(上)
|
5天前
|
JavaScript 前端开发
揭秘 `nextTick`:解决异步回调的利器(下)
揭秘 `nextTick`:解决异步回调的利器(下)
揭秘 `nextTick`:解决异步回调的利器(下)
|
5天前
|
监控 前端开发 JavaScript
async/await:使用同步的方式去写异步代码
async/await:使用同步的方式去写异步代码
58 1
|
5月前
|
前端开发
setState异步问题
setState异步问题
38 0
|
7月前
3 # 通过回调函数处理异步并发问题
3 # 通过回调函数处理异步并发问题
25 0
|
9月前
|
前端开发
react中setState是同步还是异步
react中setState是同步还是异步
72 0
|
9月前
|
JavaScript 前端开发
批量异步更新策略及 nextTick 原理?
批量异步更新策略及 nextTick 原理?
69 0
|
11月前
|
JavaScript 前端开发 API
深入理解Vue中的异步更新机制和$nextTick方法
在Vue开发中,我们经常会遇到需要在 DOM 更新完成后执行某些操作的情况。为了解决这个问题,Vue提供了`$nextTick`方法,它可以让我们在下次 DOM 更新完成后执行回调函数。本文将深入探讨Vue的异步更新机制、`$nextTick`的原理和使用场景,以及分别在 Vue2.x 与 Vue3.x 中的相同点和区别。
12484 48
深入理解Vue中的异步更新机制和$nextTick方法