【React Conf 2021】React 18 for app developers 篇章笔记

419 阅读6分钟

该系列为 React Conf 2021 分享专题的文字摘录,旨在除核心内容之余,了解分享会上其他的更为细节的内容。

笔记会携带个人理解并可能大量使用自己归纳的话术,可能会产生部分理解偏差, 如有错误理解欢迎指正! 推荐您有时间仍可观看视频内容,来了解原生分享内容。

React 18 for app developers

分享者:Shruti Kapoor

主要内容:

  • what's new in React18?
  • How to upgrade to React18?
  • It's hard to upgrade an exsiting app?

视频地址:React 18 for app developers

React Conf 2021完整视频地址:React Conf 2021 Replay

what's new in React18?(React 18 版本有什么新功能/特性)

  • Automatic batching(自动批处理)
  • Suspense on the server(Suspense将支持在服务端上进行使用)
  • New APIs for app and library developers(提供给普通开发者和库开发者的新的API)

Automatic batching(自动批处理)

React v18 废弃了并发模式,而采用一种并发特性进行取代。

React v18 之前,React 在处理状态更新时,会进行批量更新;但是当状态的更新脱离事件时,将不会批量更新,例如在一个异步方法中。

function handleClick() {
  setIsFetching(false);
  setError(null);
  setFormStatus('success');
}  // re-render 1 times

function handleClick() {
  fetch('/something').then(() => {
    setIsFetching(false); // re-render
    setError(null);       // re-render
    setFormStatus('success'); // re-render
  })
}

React v18 将这种情况(脱离事件执行)也纳入批量更新的范围自动批处理,也就是说在 v18 中,上述的三次更新将会变为1次,而这种更少的渲染次数可以带来更高的性能表现。

同时可以借助 flushSync 这一 api 来使用同步的更新模式。

Suspense on the server(Suspense将支持在服务端上进行使用)

什么是服务端渲染技术?

简单来说服务端渲染(SSR server-side render)技术是一种在服务端生成 HTML 并发送到前端的能力,以便于在加载JS包和页面可交互之前,用户可以查看到一部分UI。

Server rendering

在 v18 版本之前,服务端渲染在完成全部渲染后才会返回给浏览器,也就是说在没有完成加载时,将什么都没有。这对于某些场景,如:页面其他部分都渲染的非常快,某一模块(组件)数据加载很慢;这种情况下,按照上述规则,用户需要等待服务器将这一模块渲染完毕后整体返回,才能看到部分UI内容(仍需要去加载js包,并且直至页面可交互)。

Before React 18:All or Nothing

在 v18 中,Suspense 将支持在服务端上进行使用,这意味着你可以使用 Suspense 人为的对这些缓慢的组成部分进行包装,令这部分内容延缓加载,后续等待这部分内容加载完毕并且有数据时,服务器渲染将会弹出这部分HTML并将其应用在页面上。

例如可以对一个评论模块进行延缓加载,其代码表现如下:

<Suspense fallback={<Spinner />}>
  <Comments />
</Suspense>

初次呈现的UI视图可能如下所示:

Suspense on the server1

模块加载完毕后如下示意:

Suspense on the server2

通过这样的方式,用户就可以尽早的看到页面,并随着 HTML 片段的渐进加载,页面的内容将逐步完整。特别的,这样的交互将发生在任意 js 和 react 文件加载完毕之前。

总结来说,Suspense 在 SSR 中的应用有以下好处:

  • 令加载缓慢的部分不再影响整体的渲染进度(One slow part doesn't slow down the whole page)
  • 令呈现尽早的被用户感知并将使用流扩展加载缓慢部分(Show initial HTML early and stream the rest)
  • 在服务器端完全集成了代码分割的优化(Code splitting fully integrated with server rendering)

New APIs for app and library developers(提供给普通开发者和库开发者的新的API)

对于普通的应用开发者,我们可以使用到的新 API 有:

  • startTransition()
  • useTransition()
  • useDeferredValue()

这些 API 被称作 concurrent features(并发功能)。其中 useDeferredValue 方法允许你标记一个值,告知 React 以一种低优先级的方式进行处理,它可以帮助您紧急的向用户提供更好视觉反馈,并推迟非紧急组件的渲染(原话为:It helps you give visual feedback to the user for an urgent update and helps you defer to rerender of components that are not as urgent.)从而达到性能优化的结果。

function Demo(props) {
  const [filters, mergeFilters] = useMergeState(defaultFilters);

  // useDeferredValue
  const deferredFilters = React.useDeferredValue(filters);

  return (
    <Fragment>
      <Filters
        filters={filters}
      />
      <Lists
        filters={deferredFilters}
        project={project}
      />
    </Fragment>
  )
}

对于上述例子,filters 为过滤器数据,分别应用于 <Filters /><Lists /> 两个组件,其中 <Lists /> 组件负责对 project 数据按照 filters 数据进行筛选并展示列表,是一个功能更重的组件,而 <Filters /> 组件提供过滤选择功能,并包含一些 hover 高亮渐变的情况。

如若不进行 useDeferredValue 处理,在进行 <Filters /> 选择时(列表在选择后刷新), 部分本身配置较差的设备中, <Filters /> 组件的 hover 高亮渐变的效果会被列表阻塞,从而产生卡顿的反馈。利用 useDeferredValue,给 <Lists /> 组件传入带有延迟标记的变量,告知 React 尽快返回 UI,并对这一部分较重的模块后置渲染更新,达到不影响高亮渐变,列表后置更新的效果。

上述例子延迟更新的前提是“部分本身配置较差的设备中”,可以理解为计算机本身速度慢的情况下(或者通过chrome控制台开启了CPU节流),只有这种场景下,才会进行延迟更新。(因此可以理解为:useDeferredValue 会根据其内部的一套判别机制来决定是否启用,而启用情况下,应用本身不会出现异常,呈现上会降级处理。)

对于库开发者,可以使用以下新 API:

  • useId()
  • useSyncExternalStore();

其中 useId 可以为组件生成唯一的 id;useSyncExternalStore 将会在《React 18 for External Store Libraries》中进行单独介绍。

How to upgrade to React18?(怎么升级到 React 18 )

升级 React 18 版本的步骤如下:

  1. 在项目中安装(或者是升级) react v18 和 react-dom v18 的 npm 包b

  2. 更改根节点的渲染写法: ReactDOM.render 修改为 ReactDOM.createRoot

// 以前的写法
const container = document.getElementById('app');
ReactDOM.render(<App />, container);

// 修改为下述写法
const container = document.getElementById('app');
const root = ReactDOM.createRoot(container);
root.render(<App />);

It's hard to upgrade an exsiting app?(对已有的 React 应用升级到 v18 版本困难吗?)

大多数应用在升级到 v18 时没有问题,或者说只需要更改少量代码后就可以正常工作。

边缘情况

  • StrictMode became stricter(but you can disable it)

严格模式将更加严格

  • flushSync() lets you opt out of automatic batching

flushSync()方法允许你对自动化批处理进行开关,当存在不兼容的第三方库或者特定不适用批量更新的场景时,可以通过flushSync()方法进行适配

  • Concurrent features may require library updates

项目中如果使用了第三方库,并期望第三方库与 v18 提供的并发特性功能互相配合使用时,可能需要等待该库的维护者进行升级后,才可以使用。