• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

javascript框架React18中使用批量更新来减少渲染次数

武飞扬头像
juejin
帮助90

前言

本文是笔者在学习setState更新机制时,在github的Discussions中看到的一篇文章。这让我更加了解了React17和React18中setState更新的不同之处。顺便自己翻译总结一下。

综述

React18默认通过批处理机制来添加开箱即用的性能改进,在应用或者代码仓库中移除了手动批量更新的机制。这个文章将会解释什么是批处理,它之前是怎么工作的,并且它改变了什么。

什么是批处理

批处理是React团队为了更好的性能,将多次更新合并成为单个渲染。React只会渲染一次即使你改变了两次state中的值。

function App() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  function handleClick() {
    setCount(c => c   1); // Does not re-render yet
    setFlag(f => !f); // Does not re-render yet
    // React will only re-render once at the end (that's batching!)
  }

  return (
    <div>
      <button onClick={handleClick}>Next</button>
      <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
    </div>
  );
}

Demo:React 17在React17中,如果是内部的事件处理,React也会进行批量更新

批量更新带来了更好的性能因为它避免了不必要的重复渲染。它也阻止了你的state只进行了一次更新,从而成为了一个半成品,同时也减少了bug的产生。这就相当于当你就点了一个菜的时候,餐馆的服务员不会立刻跑到厨房告诉后厨,而是等你点完所有的菜之后,才会把菜单提交上去。

然而,React并没有在所有的更新事件中都采用批处理的方式。比如,当你点击之后访问数据,更新state 状态等,React并没有采用批处理的方式进行更新,而是分别的进行更新。

这是因为React只会在浏览器事件中采用批处理(像点击事件),但是我们更新state的状态是在fetch的回调函数中进行的。

function App() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  function handleClick() {
    fetchSomething().then(() => {
      // React 17 and earlier does NOT batch these because
      // they run *after* the event in a callback, not *during* it
      setCount(c => c   1); // Causes a re-render
      setFlag(f => !f); // Causes a re-render
    });
  }

  return (
    <div>
      <button onClick={handleClick}>Next</button>
      <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
    </div>
  );
}

🟡 Demo: React 17不会在它不能控制的事件中采用批处理。 在React 18之前,我们只在React能控制的事件处理程序中批量更新。默认情况下,promise、setTimeout、原生事件处理程序或任何其他事件内部的更新不会在React中批量执行。

什么是自动批量更新

React18中用createRoot代替了render,所有的更新都会是自动的批量更新,无论他们是从哪里产生的。

这意味着timesout,promise,原生的事件处理或者其他的事件都会被当成React内部事件进行批量更新。这将会减少rendering的次数,也会带来更好的性能。

function App() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  function handleClick() {
    fetchSomething().then(() => {
      // React 18 and later DOES batch these:
      setCount(c => c   1);
      setFlag(f => !f);
      // React will only re-render once at the end (that's batching!)
    });
  }

  return (
    <div>
      <button onClick={handleClick}>Next</button>
      <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
    </div>
  );
}

Demo1:React 18在React18中使用createRoot都会采用批处理更新的方式

🟡 Demo2: React 18 没有使用createRoot不会进行批处理更新

function handleClick() {
  setCount(c => c   1);
  setFlag(f => !f);
  // React will only re-render once at the end (that's batching!)
}
setTimeout(() => {
  setCount(c => c   1);
  setFlag(f => !f);
  // React will only re-render once at the end (that's batching!)
}, 1000);
fetch(/*...*/).then(() => {
  setCount(c => c   1);
  setFlag(f => !f);
  // React will only re-render once at the end (that's batching!)
})
elm.addEventListener('click', () => {
  setCount(c => c   1);
  setFlag(f => !f);
  // React will only re-render once at the end (that's batching!)
});

上述几种方式都会产生一样的效果。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/taneghh
系列文章
更多 icon
同类精品
更多 icon
继续加载