• React - React v18 的 批处理


    一、批处理

    批处理是 React将多个状态更新分组到单个re-render中以获得更好的性能的操作。

    例如,如果你在同一个点击事件中有两个状态更新,React 总是将它们分批处理到一个重新渲染中。如果你运行下面的代码,你会看到每次点击时,React 只执行一次渲染,尽管你设置了两次状态:

    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>
      );
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    这对性能非常有用,因为它避免了不必要的重新渲染。它还可以防止您的组件呈现仅更新一个状态变量的“半完成”状态,这可能会导致错误。

    在 React 18 之前,我们只在 React 事件处理程序期间批量更新。默认情况下,React 中不会对 promise、setTimeout、原生事件处理(native event handlers)或其它React默认不进行批处理的事件进行批处理操作。

    二、setState 的批处理

    React 18 之前

    在 React 18 之前,React 只能在组件的生命周期函数或者合成事件函数中进行批处理。

    默认情况下,Promise、setTimeout 以及原生事件中是不会对其进行批处理的。如果需要保持批处理,则可以用 unstable_batchedUpdates 来实现,但它不是一个正式的 API。

    handleClick = () => {
      setTimeout(() => {
        console.log('setTimeout 更新之前:', this.state.num); // 0
        this.setState(state => ({ num: state.num + 1 }))
        console.log('setTimeout 更新之后:', this.state.num); // 1
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    import ReactDOM from 'react-dom'
    const { unstable_batchedUpdates } = ReactDOM
    
    handleClick = () => {
      setTimeout(() => {
        unstable_batchedUpdates(()=>{
    	  console.log('setTimeout 更新之前:', this.state.num); // 0
    	  this.setState(state => ({ num: state.num + 1 }))
    	  console.log('setTimeout 更新之后:', this.state.num); // 0
      	})
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    React 18 之后

    从 React 18的createRoot开始,所有更新都将自动批处理,无论它们来自何处。

    这意味着timeouts, promises, native event handlers或任何其他事件内的更新将以与 React 事件内的更新相同的方式进行批处理。

    handleClick = () => {
      setTimeout(() => {
        console.log('setTimeout 更新之前:', this.state.num); // 0
        this.setState(state => ({ num: state.num + 1 }))
        console.log('setTimeout 更新之后:', this.state.num); // 0
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果想在 React 18 退出批处理,官方提供了一个 API flushSync。

    import { flushSync } from 'react-dom'; // Note: react-dom, not react
    
    function handleClick() {
      flushSync(() => {
        setCounter(c => c + 1);
      });
      // React has updated the DOM by now
      flushSync(() => {
        setFlag(f => !f);
      });
      // React has updated the DOM by now
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    三、React 的渲染模式

    React 批处理方式的改变,主要是因为改变了渲染模式,React 目前有三种渲染模式

    1. legacy 模式:ReactDOM.render(, rootNode)。React 18 前的设计模式,这将创建一个以“遗留”模式运行的 root。使用此 API 会有一个警告,表明它已被弃用并切换到 New Root API。
    2. blocking 模式:ReactDOM.createBlockingRoot(rootNode).render() 。可以视为 concurrent 的优雅降级版本和过渡版本
    3. concurrent 模式 :ReactDOM.createRoot(rootNode).render()。这将创建一个在 React 18 中运行的 root,它添加了 React 18 的所有改进并允许使用并发功能。React 18 采用的模式,拥有不同的优先级,更新的过程可以被打断。

    legacy 模式,根据 isBatchUpdate 判断是否批量更新,在 React 事件中有自动处理批更新的功能。非 React 事件想使用这个功能必须使用 unstable_batchedUpdates。

    concurrent 模式,是以优先级为依据对更新进行合并的。 每次更新会进行优先级的判定,相同优先级的任务会被合并,所有的 setState 在默认情况下都是批处理更新的。


    参考链接:
    Automatic batching for fewer renders in React 18
    Automatic Batching in React 18: What You Should Know
    一探那些令人興奮的 React 18 三大新 features
    React18 setState之 Automatic batching
    一篇带给你 React 18 升级指南

  • 相关阅读:
    Python 继承和子类示例:从 Person 到 Student 的演示
    Android 实战项目:简单计算器
    py4_简单接触 Python 正则表达式
    《从0开始写一个微内核操作系统》6-GIC中断
    Java对象与封装详解
    raft算法的自我理解
    DevOps(九)Selenium 介绍和Jenkins集成
    python强制停止线程学习
    Lua 协程 + 过滤器实现生产者和消费者
    ZooKeeper 核心知识总结
  • 原文地址:https://blog.csdn.net/kelly0721/article/details/126821172