javascript - 在React中,到底什么时候决定重新渲染?

标签 javascript reactjs

我对 React 何时决定重新渲染感到困惑。

function App() {
  const [position, setPosition] = useState({x: 0, y: 0});

  console.log(position);

  const handleMove = (e) => {
    const newPos = {x: e.clientX, y: e.clientY};
    setPosition(newPos);
    position.x = e.clientX;
    position.y = e.clientY;
    setPosition(position);
  };

  return (
    <div onPointerMove={e => {
      handleMove(e);
    }}>
      <h1>{position.x}</h1>
      <h1>{position.y}</h1>
    </div>
  );
}

上面的代码来 self 的 React 组件函数。

在此代码中,您可以看到我正在改变用作状态的对象。虽然这是 React 禁止的方法,但我还是出于实验目的编写了这段代码。

对原始对象进行变异,然后调用setState函数后,不会发生重新渲染。为了强制重新渲染,我创建并分配了 newPos,然后重新分配了原始位置对象。

记录后,我注意到我的组件函数被不断调用,并且位置的 x 和 y 值不断更新。我还确认在返回的 JSX 对象中,position.x 和position.y 值正在发生变化。

但是,实际网页并未反射(reflect)这些更改。可能是什么原因? JSX返回后,比较现有DOM和新创建的DOM的过程中,重新渲染是否被拒绝?但 JSX 中的值(value)观已经明显改变。

有谁能给出明确的答案吗?

最佳答案

我认为理解这一点的最好方法是将其视为两个单独的行为,单独来看,每个行为都有意义:

  1. 状态正在更改(通过 setPosition(newPos)),因此 React 安排一个新的调用来渲染组件。该新调用将在 batching 之后看到最新状态。 ,包括 position 对象的当前内容。
    • 这看起来很合法,对吧?状态确实发生了变化,那么为什么 React 不应该重新调用组件函数呢?
    • 当然,如果它足够聪明,可以在这种情况下跳过渲染组件(因为当它调用它时,状态已经变回原来的状态),那么可能会更好,但是什么也没有渲染错误
  2. 但是状态改变最终并没有真​​正发生(因为 setPosition(position) 撤销了 setPosition(newPos) - 显然 React 从未检查过,更不用说存储了position 的内容,所以它只知道它是同一个对象); React 会检测到这一点,并跳过渲染后步骤:它不会递归遍历新结果和旧结果来查看更改的内容,它不会重新渲染任何属性已更改的子组件,正如您所见,它不更新 DOM。
    • 这看起来也合法,对吧?状态最终是相同的,那么为什么 React 应该重做所有这些工作呢?
    • 当然,如果 React 没有这种优化,并且即使结果没有状态更改它也执行了所有渲染后步骤,那也可以OK ;但是,很高兴它有这种优化。

总的来说,我同意这些行为看起来很奇怪——如果组件函数最终没有实际使用结果,为什么还要费力地重新调用组件函数呢? ——但是,当然,这不是计算机“思考”的方式。渲染后步骤有一个“哦,等等,状态又变回来了!”优化,但他们不负责告诉渲染步骤如何完成其​​工作。

请注意,渲染后步骤通常比渲染本身要昂贵得多,因此即使在当前形式下,优化也是有用的;但如果 R​​eact 的 future 版本包含您显然期望的优化(在这种情况下完全跳过渲染函数),我一点也不感到惊讶。


顺便说一句,这一点:

    <div onPointerMove={e => {
      handleMove(e);
    }}>

在每个渲染上指定一个新的/不同的pointerMove处理程序。在您不仅仅是进行试验的真实组件中,您可能想要使用 the useCallback hook以避免导致子组件不必要的重新渲染和(更糟糕的是)不必要的 DOM 更新。

关于javascript - 在React中,到底什么时候决定重新渲染?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77653432/

相关文章:

reactjs - 在 setTimeout 内多次更新状态

reactjs - 从单个文件导出的 Material UI v4 makeStyles 不会在刷新时保留样式

javascript - 服务器渲染错误

javascript - 如何使用 JavaScript 将新元素添加到引用另一个元素的多个位置的 JSON 对象?

javascript - HTTP header 变为小写

javascript - 你如何使用 jQuery 创建一个整数字符串?

javascript - 访问传递给原型(prototype)函数的值

javascript - 如何反转 react native 矢量图标按钮颜色?

javascript - 子组件中的 React 和方法

javascript - 从容器外部访问生命周期方法的变量