1. Automatic batching

以往在事件中setState,react会将多个set操作合并成一次,例如: sandbox

function handleClick() {
  console.log("=== click ===");
  setCount((c) => c + 1);
  setFlag((f) => !f);
}
// // 两次set会被合并处理

但是在异步操作中比如:setTimeout 或 fetch,set操作并不会合并。sandbox

function handleClick() {
    console.log("=== click ===");
    fetchSomething().then(() => {
      // React 17 and earlier does NOT batch these:
      setCount((c) => c + 1); // Causes a re-render
      setFlag((f) => !f); // Causes a re-render
    });
  }

所以有些第三方库会手动合并:

import { unstable_batchedUpdates } from 'react-dom';

unstable_batchedUpdates(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
});
// 两次set会被合并处理

React18 将提供自动批处理功能,只要使用ReactDOM.createRoot,代替ReactDOM.render。
若部分需求不想使用批处理,可以使用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
}

2. Behavioral changes to Suspense in React 18

React官方将18版本的Suspense称作"Concurrent Suspense",16、17版本的Suspense称作"Legacy Suspense"。

以下面代码为例:

<Suspense fallback={<Loading />}>
  <ComponentThatSuspends />
  <Sibling />
</Suspense>

区别在于被挂起的组件的兄弟节点。
在Legacy Suspense中 ,Sibling 会立即挂载到DOM中,并触发生命周期。sandbox

在Concurrent Suspense,其兄弟节点Sibling 组件没有立即挂载到 DOM。它的effect/生命周期也不会在 ComponentThatSuspends 解决之前触发。sandbox
其目的是延迟子树的渲染,直到树中的所有数据都已解析。

3.New feature: startTransition

属于一个性能优化的API,以下结论参考:Real world example: adding startTransition for slow renders


解决什么问题

目前我把它理解为:更聪明的防抖截流,方便理解
官方提供了一个很具体例子(例子具体的好处是方便理解startTransition的作用,但也有坏处,就是除此之外我在想不到他的用处):

做可视化时可能遇到,有一个滑块,可以调节阈值,滑块下边是一个关系图。
滑动滑块,阈值变化引起数据变化,数据变化引起关系图变化


好的实现:2021-06-22.at.9.42.18.AM.mov
一般实现:2021-06-21.at.3.43.50.PM.mov
无任何优化的实现:2021-06-21.at.1.16.51.PM.mov



如何解决的

Updates wrapped in startTransition are handled as non-urgent and will be interrupted if more urgent updates like clicks or key presses come in. If a transition gets interrupted by the user (for example, by typing multiple characters in a row), React will throw out the stale rendering work that wasn’t finished and render only the latest update.

包含在 startTransition 中的更新被视为非紧急更新,如果出现更紧急的更新(如点击或按键),则会被中断,如果transition被用户打断(例如,通过在一行中输入多个字符),React 将丢弃未完成的陈旧渲染工作并仅渲染最新更新。

Yielding: every 5 ms, React will stop working to allow the browser to do other work, like run promises or fire events.
  • 让渡:每 5 毫秒,React 将停止工作以允许浏览器执行其他工作,例如运行promise或触发事件。

    Interrupting&Skipping old results:: If a transition gets interrupted by the user (for example, by typing multiple characters in a row), React will throw out the stale rendering work that wasn’t finished and render only the latest update.
  • 打断&舍弃旧结果:如果transition被用户打断(例如,通过在一行中输入多个字符),React 将丢弃未完成的陈旧渲染工作并仅渲染最新更新。

与setTimeout的不同

  • setTimeout is Asynchronous but startTransition is synchronous.


v2-95b130df7d26e64a4ef8925cedd0555e_b.gif
We can see that startTransition doesn't change the order of events, it is still there but it will "wait" urgent events to finish then it will execute.
gif来自:知乎



yzbao
626 声望19 粉丝

Uncaught ReferenceError


« 上一篇
code-splitting