3 月 8 日,React 团队发布了 React 18 RC(Release Candidate)。最新版本带来了许多新功能,可以改变许多应用程序中的编码模式。它带来了一些性能改进,我将在本博客中介绍这些改进。

并发

并发是系统的一种属性,其中多个进程同时执行,并且可能会或可能不会相互交互。太复杂了?让我们分解一下。假设正在进行一场比赛。现在,并发是有多少人在平行赛道上参加一场比赛。

并发

并发是 React 18 引入的一个新特性。它是一种新的幕后机制,使 React 能够同时准备多个版本的 UI

在这种机制下,与以前的情况不同,React 可能会开始渲染,中间暂停一些关键任务,然后再次恢复渲染。唯一要记住的是,它也可能完全放弃进程渲染。即使渲染中断,React 也能保证 UI 看起来是一致的。

这使 React 能够在后台准备屏幕 - 不会阻塞新线程!

服务端渲染的悬念

服务端渲染的悬念

React 在 Next.js、Relay、Hydrogen 或 Remix 等服务器端渲染框架中带来了 Suspense 的特性。React 18 引入:有悬念 的服务端代码拆分,服务端 Streaming 渲染

自动配料

批处理是 React 将多个状态更新分组到一个重新渲染中以实现更好的性能优化的现象。

动图配料

在 React 18 之前,对基于反应的事件处理程序执行批量更新。但是对于promises、setTimeouts、本机事件处理程序或任何其他事件,没有执行批量更新。React 18 也针对上述情况执行自动批量更新。

让我们使用代码来理解这一点。

setTimeout(() => {
  setCount(count => count + 1);
  setFlag(flag => !flag);
  // React will only re-render once at the end (that's batching!)
}, 1000);

同样,上述代码的行为与此相同:

fetch(/*...*/).then(() => {
  setCount(counter => counter + 1);
  setFlag(flag => !flag);
  // React will only re-render once at the end (that's batching!)
})

如果您不想批处理,可以使用ReactDOM.flushSync(). 让我们用一点代码来理解

import { flushSync } from 'react-dom'; // Note: react-dom, not react

function handleFlushesClick() {
  flushSync(() => {
    setCounter(counter => counter + 1);
  });
  // React has updated the DOM by now
  flushSync(() => {
    setFlag(flag => !flag);
  });
  // React has updated the DOM by now
}

过渡

此功能区分紧急和非紧急更新。紧急更新是需要立即响应的更新。紧急更新包括点击、按下、键入等操作——需要立即响应或用户希望 UI 立即响应的操作。 屏幕上不会显示任何中间值。

动图过渡示例

一个真实的例子

考虑一个现实生活中的例子,让我们考虑一个去抖动的 typeahead。现在,当您输入输入时,您希望输入框反映输入的值。但是,您希望结果立即出现吗?没有权利!它会去抖动,然后你会得到结果。因此,从您输入输入到您收到建议之间有一段过渡时间。这个时间框架将用于过渡。

通常,为了获得最佳用户体验,单个用户输入应导致紧急和非紧急更新。

import {startTransition} from 'react';

// Urgent: Show what was typed
    setInputValue(input);`

// Mark any state updates inside as transitions
  startTransition(() => {
     // Transition: Show the autosuggestion based on the input 
        value
      setSearchQuery(input);
});

动图搜索栏

另一个实时示例

const [isPending, startTransition] = useTransition()

这里 useTransition 钩子有 2 个被解构的参数。

isPending: 表示 UI 更新是否仍处于过渡状态

startTransition:执行事务代码的函数。

function handleClick() {
   startTransition(() => {
     setTab('comments');
   });
}

当您想从照片选项卡切换到评论选项卡时,会调用此函数。

`<Suspense fallback={<Spinner />}><div style={{ opacity: isPending ? 0.8 : 1 }}>{tab === 'photos' ? <Photos /> : <Comments />}</div></Suspense>`

在过渡阶段,当 React 正在准备新的 UI 时,带有照片 UI 的选项卡现在将以 80% 的不透明度向用户显示,以提供平滑的过渡视图。

React 中的严格模式

开发服务器中的严格模式在 React 18 中带来了一些有趣的变化。这种模式本质上为 React 提供了开箱即用的性能。

每当第一次安装组件时,此新检查将自动卸载并重新安装每个组件,并在第二次安装时恢复先前的状态。

现在安装期间的一系列事件:

I. React 挂载组件。

  • 创建布局效果。
  • 创建效果。

二、React 模拟卸载组件。

  • 布局效果被破坏。
  • 效果被破坏。

三、React 模拟使用先前状态安装组件。

  • 创建布局效果。
  • 效果已创建。`

在卸载期间,会发生以下事件

I. 布局效果被破坏,Effect 效果被破坏。

新钩子

图片描述

一种。使用 ID

useId 是一个新的钩子,用于在客户端和服务器上生成*唯一 ID *,同时避免水合不匹配。这会生成一个包含 : 的 unique 字符串,它不会与 css 选择器和querySelectorAll冲突

您还可以将 userId 与 identifierPrefix 一起使用,以防止多根应用程序中的冲突。对于同一组件中的多个 ID,请使用相同的 id 附加后缀。

湾。使用延迟值

useDeferredValue 将允许您推迟重新渲染树的非紧急部分。还记得我们讨论过非紧急渲染吗? 它没有固定的时间延迟,因此 React 将在第一次渲染反映在屏幕上之后立即尝试延迟渲染。

C。使用同步外部存储

useSyncExternalStore 是一个新的钩子,它允许外部存储通过强制对存储的更新同步来支持并发读取。在实现对外部数据源的订阅时,它消除了对 useEffect 的需求。

代码片段:

   const state = useSyncExternalStore(subscribe, getSnapshot[, getServerSnapshot]);

subscribe: 注册回调的函数,每当商店更改时调用该回调。 getSnapshot:返回商店当前值的函数。 getServerSnapshot:返回服务器渲染期间使用的快照的函数。

d。使用插入效果

useInsertionEffect(didUpdate);

useInsertionEffect 是一个新的钩子,它允许 CSS-in-JS 库解决在渲染中注入样式的性能问题。这个钩子将在 DOM 发生变异之后运行,但在布局效果读取新布局之前。

这个钩子将有助于计算与并发重新渲染同步的布局。


结论

还有其他一些小但重要的更新——例如使用createRoot()钩子而不是ReactDOM.render. 此方法将用于渲染 DOM 元素并使用 umountroot.unmount()

除了 React 之外,还有对使用renderToPipeableStream&的服务器的流式 Suspense 支持renderToReadableStream

React 开发人员继续关注此发布版本中的增强和改进以及几个错误修复。更新并不细致,可以在早上的会议中完成,本身。那么,应用程序开发人员还等什么呢?让我们升级我们的库并开始工作吧!向 React 团队致敬!