返回

深入解析 setState 的那些不为人知

前端

前言

setState 算是 React 里被使用的最高频的 api,但你真的了解 setState 吗?比如下面这段代码,你能清楚的知道控制台输出什么吗?

class App extends React.Component {
  state = {
    count: 0
  }

  componentDidMount() {
    this.setState({ count: 1 });
    console.log(this.state.count); // 0
    this.setState({ count: 2 });
    console.log(this.state.count); // 0
    setTimeout(() => {
      this.setState({ count: 3 });
      console.log(this.state.count); // 3
    }, 0);
  }

  render() {
    return <div>{this.state.count}</div>
  }
}

相信不少人都会很诧异,控制台的输出结果是 0、0、3。为什么会出现这种情况呢?我们先来了解一下 setState 的工作原理。

setState 的工作原理

当我们调用 setState 函数时,React 会将新的 state 合并到当前的 state 中,然后将组件标记为需要重新渲染。但是,React 并不是立即执行重新渲染,而是将重新渲染任务加入到一个队列中。当浏览器空闲时,React 会从队列中取出需要重新渲染的组件,并执行重新渲染。

这意味着,如果我们在短时间内多次调用 setState 函数,React 只会将这些 state 合并到一起,然后将组件标记为需要重新渲染一次。只有当 React 真正执行重新渲染时,我们才能看到最新的 state。

这就是为什么在上面的代码中,控制台输出的结果是 0、0、3。当我们第一次调用 setState 函数时,React 将新的 state 合并到当前的 state 中,并将组件标记为需要重新渲染。但是,此时 React 并不会立即执行重新渲染,而是将重新渲染任务加入到队列中。

当我们第二次调用 setState 函数时,React 再次将新的 state 合并到当前的 state 中,并将组件标记为需要重新渲染。但是,此时 React 仍然不会立即执行重新渲染,而是继续将重新渲染任务加入到队列中。

当我们第三次调用 setState 函数时,React 终于将重新渲染任务从队列中取出,并执行重新渲染。此时,组件的 state 已经更新为最新的 state,因此控制台输出的结果是 3。

setState 的注意事项

了解了 setState 的工作原理后,我们需要注意以下几点:

  1. setState 是异步的。这意味着当我们调用 setState 函数时,我们无法立即看到最新的 state。
  2. setState 是批量的。这意味着如果我们在短时间内多次调用 setState 函数,React 只会将这些 state 合并到一起,然后将组件标记为需要重新渲染一次。
  3. setState 的性能开销。由于 setState 是异步的,并且 React 会将多次 setState 合并成一次重新渲染,因此 setState 会带来一定的性能开销。

如何优化 setState 的性能

为了优化 setState 的性能,我们可以做以下几点:

  1. 避免在短时间内多次调用 setState 函数。
  2. 使用 shouldComponentUpdate 函数来控制组件的重新渲染。
  3. 使用 PureComponent 类来减少组件的重新渲染次数。

总结

setState 是 React 中一个非常重要的函数,但它也是一个容易被误解的函数。本文介绍了 setState 的工作原理和注意事项,并提供了优化 setState 性能的技巧。希望本文能够帮助你更好地理解和使用 setState 函数。