返回

React 源码阅读:setState 是异步的吗?原来你理解错了!

前端

React 源码系列文章是深入理解 React 工作原理的必读书目。相信很多同学都曾经被 setState 的异步行为困惑过,今天我们就来一探究竟。

在一个 React 组件中,我们使用 setState() 来更新组件的状态。在阅读源码之前,我们先来看看一个简单的例子:

import React, { useState } from "react";

function MyComponent() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
    setCount(count + 1);
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
}

export default MyComponent;

当我们点击按钮时,handleClick 函数会被调用,然后 setCount 函数会被调用三次,每次都会将 count 的值增加 1。但是,当你点击按钮时,你会发现 count 的值只增加了 1。这是什么原因呢?

原来是这么一回事!

实际上,setState 是异步的。这意味着当我们调用 setState 时,React 不会立即更新组件的状态。相反,它会将状态更新放入一个队列中,然后在稍后一次性更新所有状态更新。

这种异步行为是为了提高 React 的性能。如果 setState 是同步的,那么每次调用 setState 时,React 都需要重新渲染组件。这可能会导致性能问题,尤其是对于大型组件。

那为什么还是出错了?

但是,在某些情况下,异步的 setState 可能会导致一些意外的行为。比如,在上面的例子中,如果我们在 handleClick 函数中直接使用 count 的值,那么就会出现问题。这是因为当我们点击按钮时,count 的值还没有被更新。

为了解决这个问题,我们可以使用一个回调函数来更新 count 的值。比如:

const handleClick = () => {
  setCount((prevCount) => prevCount + 1);
  setCount((prevCount) => prevCount + 1);
  setCount((prevCount) => prevCount + 1);
};

这样,我们就可以确保在更新 count 的值之前,count 的值已经被更新了。

总结

异步的 setState 是 React 的一个重要设计思想。它可以提高 React 的性能,但也有可能导致一些意外的行为。因此,在使用 setState 时,需要特别注意其异步行为。

附录