关于 React 18 RC 你需要知道的一切

2025-05-27

关于 React 18 RC 你需要知道的一切

对于 React 社区的每个人来说,这是一个非常激动人心的消息: React 18 RC(候选版本)已于 2022 年 3 月 8 日发布这意味着所有功能都已最终确定,距离 React 18 的正式发布仅剩几周时间。对于那些一直关注这个新版本的人来说,你们知道这已经等了很久了——React 17于 2020 年 10 月发布(众所周知的“无功能”版本)。React 18 的第一个 Alpha版本于 2021 年 6 月发布,随后于 2021 年 11 月发布了Beta 版本

现在我们已进入最后冲刺阶段,所以现在正是了解所有即将推出的激动人心的新特性并开始思考 React 18 能为你的应用带来哪些功能的绝佳时机!不过别担心——我一直在观看React Conf 视频,关注React 工作组的讨论,并阅读所有博客文章,这样你就不用费心了。话虽如此,让我们来看看你应该了解的关于 React 18 的所有重要内容!

React 专注于设计

如果你之前读过我的文章,你就会知道,我最热衷的事情之一就是帮助弥合设计师和开发者之间的差距。正因如此,我特别兴奋地看到 React 工程师 Andrew Clark 在2021 年 React Conf 的 React 18 主题演讲中,详细阐述了 React(尤其是 React 18 的新功能)是如何基于设计原则的。

React 的 API 主要根植于设计原则,而不是编程
React 18 Keynote幻灯片的截图

在 React 18 的开发过程中,团队不仅咨询了开发者,还咨询了设计师和用户体验专家——我相信,您可以从本次 RC 版本中展示的新功能中看到这一点。正如 Andrew 在主题演讲中所说:“有了 React,设计师和开发者就能使用同一种语言。”

React 如此注重 UI,一直以来都吸引着设计导向的团队和开发者——这也是我如此热爱它的重要原因!很高兴看到团队真正地致力于此,在主题演讲中也提到了这一点,并积极与设计师和其他 UI/UX 专业人士合作,进一步开发和改进这个库。

并发渲染

如果要用一个词来概括整个 React 18 版本,那绝对是“并发”并发是一项幕后功能,它为本次更新中的许多功能提供支持,例如 Suspense 以及新的startTransition()API useDeferredValue()

从高层次上讲,并发基本上意味着任务可以重叠。系统不必等到某个状态更新完全完成后才能继续执行下一个状态更新,而是可以在多个状态更新之间来回切换。需要注意的是,这并不意味着所有任务都 同时发生——而是说,现在可以 暂停一个任务,同时处理其他更紧急的任务。然后,一旦更紧急的任务完成,我们就可以跳回到不那么紧急的任务,并将更紧急任务的更新信息带回给我们。

React 18 为我们提供了(非常 的)处理和操控并发流的工具。现在,开发者对渲染优先级和顺序的控制比以往任何时候都更加强大。

悬念

React 的一大优点是其代码的可读性。开发人员可以轻松打开文件,从上到下阅读代码,从而快速了解组件内部的具体情况。

然而,当我们需要获取和处理数据时,这种便捷性就消失了。开发人员通常会求助于数据获取库,例如 Apollo 或 React Query,它们提供了 API 和钩子,让他们可以省去这些复杂的操作。

即使有了这些解决方案,仍然有其他问题需要解决——主要是数据和加载状态的内在关联方式。以前,我们必须指定某种加载状态,然后编写相应的 JSX 代码来根据该状态进行条件渲染。这意味着我们的 UI 元素始终与特定数据的加载状态绑定在一起。

const [loading, setLoading] = useState(true);

if myData != null {
    setLoading(true); 
} 

<>
    { !loading && 
        <MyComponent />
    }
    { loading && 
        <Loading />
    }
<>
Enter fullscreen mode Exit fullscreen mode

Suspense通过允许我们为尚未准备好显示的 UI 元素指定后备来解决该问题。

<Suspense fallback={<Loading/>}>
    <MyComponent myData={myData}/>
</Suspense> 
Enter fullscreen mode Exit fullscreen mode

有趣的是,它的设计灵感源自设计原则——具体来说,就是骨架布局的概念。在骨架布局中,UI 元素始终处于原位,并在内容准备就绪时进行填充。这种方法可以帮助开发者编写更贴近实际设计的代码,从而缩小原型和实际应用之间的差距。

这种方法使我们更容易重新设计页面的 UI——哪些内容需要一起加载还是单独加载,何时加载以及在何处加载——因为我们只需添加新<Suspense>组件(甚至可以嵌套在其他<Suspense>组件中!)或将其他元素移入或移出现有<Suspense>组件即可快速重新排列页面布局。由于<Suspense>组件本身并不像我们以前那样与特定数据绑定,因此它将 UI 代码与功能代码分离,从而真正优先考虑设计体验。

不过,我们不仅限于将 Suspense 用于数据,我们还可以将其用于流式服务器渲染。

流服务器渲染

服务器渲染是一种技术,它会渲染 React 组件的 HTML 输出,然后在 JS 准备好之前将其发送到客户端,这样用户就不会被困在一个完全空白的页面上。在 React 18 之前,服务器渲染是全有或全无的——当所有组件都准备好后,页面就会更新,用户就可以开始与应用程序交互了。这意味着,如果你有一个非常慢的组件,比如一个复杂的数据网格,那么这个组件就可能造成瓶颈。

服务器端渲染的视觉示例
图片来自《React 18 for App Developers》幻灯片。

现在,我们有了 Suspense!就像我们之前讨论过的那样,我们可以用这些<Suspense>标签包裹一个加载缓慢的组件,并告诉 React 延迟该组件的加载,转而专注于优先加载其他加载速度较慢的组件。你还可以像之前提到的那样,设置 fallback 来显示加载动画。

服务器上 Suspense 的可视化示例
图片来自《React 18 for App Developers》幻灯片。

这样,用户就可以在页面内容可用时立即逐个组件地查看,而不必等待所有内容准备就绪后再一次性获取所有内容。您可以立即显示初始 HTML,然后再流式传输其余内容!

自动配料

React 18 中另一个重大升级是自动批处理。在深入探讨 React 18 带来的变化之前,我们先来了解一下什么是批处理。

以前,批处理发生在单个事件处理程序中有多个状态更新时;在这种情况下,React 只会在函数结束时重新渲染一次,而不是每次状态更改时都重新渲染。但是,这不会在事件处理程序之外发生——例如,如果在 fetch 调用中有多个状态更新,那么代码为每次更新重新渲染。

fetch('http://example.com/data.json').then(() => {
    setIsLoading(false); 
    setData(data);
    setError(null);
});

// Previously this code would cause 3 different re-renders, once for each state update. 
// Now, these three updates will be batched together into 1 re-render. 
Enter fullscreen mode Exit fullscreen mode

现在,无论更新 被什么包裹,都会自动批量处理。这将大大提高代码效率,并避免不必要的重新渲染。但是,如果需要,您可以选择在特定情况下进行重新渲染。

新的 API

startTransition()

当我们使用 startTransition API 时,我们所做的就是将一些不太紧急的操作标记为“转换”,然后告诉 React 让其他更紧急的操作在渲染时间轴中优先执行。

从用户体验的角度来看,这是一个 非常棒的 更新。它会让用户体验更加流畅、响应更快,同时减少我们开发者的工作量,从而最大程度地减少这一痛点。通过将那些速度较慢、不太紧急的更新包装到 中 startTransition,我们基本上可以告诉 React,当它没有更重要的事情要做时,就可以直接处理这些更新。

这意味着过渡可以被更紧急的更新打断,React 会直接丢弃未完成、现已过时的渲染工作,直接跳转到新的内容。这也意味着我们永远不会因为渲染过时且不准确的数据而浪费时间。或者更糟糕的是,用户看到的信息不再正确。

onChange = (e) => {
  const value = e.target.value;
  startTransition(() => {
    nonUrgentAction(value);
  });
};
Enter fullscreen mode Exit fullscreen mode

useTransition()

由于您的整个页面将不再被锁定以等待这些漫长的过程,您的用户甚至可能没有意识到任何内容仍在加载!

因此,建议使用 isPending React 18 中附带的值作为 useTransition 钩子的一部分。此钩子会返回 startTransition 函数以及  在过渡渲染时 isPending 将设置的值 。这样,您可以快速 检查是否需要调整 UI 以反映更新尚未完成的事实,例如禁用按钮。trueisPending

const [isPending, startTransition] = useTransition();

<Button className={isPending ? 'disabled' : 'active'} />
Enter fullscreen mode Exit fullscreen mode

useDeferredValue()

新的useDeferredValue()API 允许我们选择 UI 中的特定部分,并有意推迟更新它们,以免拖慢页面其他部分的加载速度。这样做有两个好处:(1) 可以控制渲染顺序;(2) 可以显示之前或旧的值,而不仅仅是加载动画或灰色框。

如上所述,这是一个非常棒的设计导向更新。没有什么比一个充满加载动画的页面更糟糕的了,很多时候,稍微过时的数据总比没有数据要好。这使得我们的组件即使真的在后台运行,也不会让人感觉它们正在加载。对用户来说,它只是……更新!多么棒啊。

以下是一个使用示例:假设我们value从一个定期更新的数据源获取数据,但数据量很大,通常需要一些时间才能加载。现在,我们可以允许在后台获取新数据,并通过让组件使用旧的 内容(最长 4000 毫秒)来useDeferredValue营造快速流畅更新的假象。value

const deferredValue = useDeferredValue(value, { timeoutMs: 4000 }); 

return (
  <div>
    <MyComponent value={deferredValue} />
  </div>
);
Enter fullscreen mode Exit fullscreen mode

说再见ReactDOM.render

需要注意的是,在 React 18 中,之前用于将应用程序挂钩到 DOM 的语法将终止使用ReactDOM.renderReactDOM.createRoot。它将被 取代,这对于支持新功能是必要的。您可以不做任何更改就升级ReactDOM.render,您的代码仍然可以工作,但您的控制台会报错,并且您将无法使用此新版本中的任何新功能。

// The old way:  
ReactDOM.render(
  <App />,
  document.getElementById('root')
);

// The new way: 
const root = ReactDOM.createRoot(document.getElementById('root')); 
root.render(<App/>);
Enter fullscreen mode Exit fullscreen mode

没有重大变化!

如果你一直关注 React 过去的更新,你可能之前就听说过“并发模式”这个词。但重要的是要知道,它现在已经过时了——并发模式不再是 React 18 使用的采用策略。取而代之的是“并发特性”。或者,正如 React 团队常说的那样,“没有并发模式,只有并发特性!”

实际上,这意味着无需“打开”任何高级标志或切换即可使用并发渲染 - 您可以根据需要在需要的地方添加并发功能,而不必担心对应用程序其余部分的影响。因为所有新的并发功能都是选择加入的- 这意味着您必须特意将操作包装在转换中来声明它 setTransition,而不是自动设置任何内容 - 您现有的代码不会受到这些更改的影响。React 18 仍会默认将所有更新视为紧急更新,除非您使用任何并发功能来告知它其他情况。这意味着您可以在准备好并且合理的情况下升级并有选择地开始将新功能应用到您的代码库中!

准备升级

那么,还在犹豫什么?升级到 React 18 RC 版快捷又简单,您可以立即在应用程序中体验所有这些强大的新功能。立即行动,只需几周即可为 React 18 的最终版本做好准备!

文章来源:https://dev.to/kathryngrayson/everything-you-need-to-know-about-the-react-18-rc-3kc6
PREV
📖 “停止 React 中不必要的重新渲染组件!!”的历史记录
NEXT
面向开发人员的设计系统