游客发表

一篇教你如何升级到 React 18

发帖时间:2025-11-04 19:24:58

这是篇教 React 官方 2022.03.08 发表的文章《How to Upgrade to the React 18 Release Candidate[1]》的译文,通过本文,何升可以对 React 18 的篇教新特性有一个全面的认知。

接下来,何升我还会翻译其它几篇比较重要的篇教 React 18 文章,以便以更好的何升姿势使用 React 18,关注不迷路。篇教

今天,何升我们发布了 React 18 RC 版本。篇教正如我们在 React Conf[2] 上分享的何升那样,React 18 基于 concurrent 模式,篇教带来了更多能力,何升同时提供了渐进升级的篇教方法。在这篇文章中,何升我们会一步一步的篇教带您升级到 React 18。

安装

使用 @rc标签来安装最新版 React。

## npm

$ npm install react@rc react-dom@rc

## yarn

$ yarn add react@rc react-dom@rc客户端渲染 API 更新

当你首次安装 React 18 的时候,你会看到如下警告:

ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it’s running React 17. Learn more: https://reactjs.org/link/switch-to-createroot[3]。

React 18 提供了更合理的初始化 API,使用该 API,会自动启用 concurrent 模式:

// Before

import { render } from react-dom;

const container = document.getElementById(app);

render(, container);

// After

import { createRoot } from react-dom/client;

const container = document.getElementById(app);

const root = createRoot(container);

root.render(<App tab="home" />);

同时我们将卸载方法从 unmountComponentAtNode 修改为 root.unmount:

// Before

unmountComponentAtNode(container);

// After

root.unmount();

我们移除了 ReactDOM.render 函数的 callback,b2b供应网因为当使用 Susponse 的时候,它会有问题:

// Before

const container = document.getElementById(app);

ReactDOM.render(, container, () => {

console.log(rendered);

});

// After

function AppWithCallbackAfterRender() {

useEffect(() => {

console.log(rendered);

});

return

}

const container = document.getElementById(app);

const root = ReactDOM.createRoot(container);

root.render(<AppWithCallbackAfterRender />);

最后,如果你使用 hydration 来实现了 SSR,需要将 hydrate 替换为 hydrateRoot:

// Before

import { hydrate } from react-dom;

const container = document.getElementById(app);

hydrate(, container);

// After

import { hydrateRoot } from react-dom/client;

const container = document.getElementById(app);

const root = hydrateRoot(container, );

// Unlike with createRoot, you dont need a separate root.render() call here.

更多信息可见 Replacing render with createRoot[4]。

SSR API 更新

在 React 18 中,为了支持服务端的 Suspense 和流式 SSR,优化了 react-dom/server 的 API。

使用以下 API,将会抛出警告:

renderToNodeStream:废弃 ⛔️️。

相反,对于 Node 环境中的流式传输,请使用:

renderToPipeableStream:新增 ✨。

我们还引入了一个新的 API,以在现代边缘运行时环境支持流式 SSR 和 Suspense,例如 Deno 和 Cloudflare workers:

renderToReadableStream:新增 ✨。

下面的两个 API 可以继续使用,但是不支持 Suspense:

renderToString:限制 ⚠️。renderToStaticMarkup:限制 ⚠️。

下面的 API 没有变化:

renderToStaticNodeStream。

更多信息可见Upgrading to React 18 on the server[5]、New Suspense SSR Architecture in React 18[6]。

自动批处理 Automatic Batching

批处理是指:React 将多个状态更新,聚合到一次 render 中执行,以提升性能。服务器租用

在 React 18 之前,只能在 React 自己的事件机制中使用批处理,而在 Promise、setTimeout、原生事件等场景下,是不能使用批处理的。

React 18 支持了更多场景下的批处理,以提供更好的性能。

// 在 React 18 之前,只有 React 事件,才会使用批处理

function handleClick() {

setCount(c => c + 1);

setFlag(f => !f);

// React 只会 re-render 一次,这就是批处理

}

setTimeout(() => {

setCount(c => c + 1);

setFlag(f => !f);

// React 会 render 两次,每次 state 变化更新一次

}, 1000);

使用 createRoot初始化 React 18 之后,所有的状态更新,会自动使用批处理,不关心应用场景。

// React 18 之后,Promise、setTimeout、原生事件中,都会自动批处理

function handleClick() {

setCount(c => c + 1);

setFlag(f => !f);

// React 只会 re-render 一次,这就是批处理

}

setTimeout(() => {

setCount(c => c + 1);

setFlag(f => !f);

// React 只会 re-render 一次,这就是批处理

}, 1000);

这是一个 break change,服务器托管但是我们希望这能提升你的产品性能。当然,你仍然可以使用 flushSync 来手动取消批处理,强制同步执行:

import { flushSync } from react-dom;

function handleClick() {

flushSync(() => {

setCounter(c => c + 1);

});

// React 更新一次 DOM

flushSync(() => {

setFlag(f => !f);

});

// React 更新一次 DOM

}

更多信息可见 Automatic batching for fewer renders in React 18[7]。

三方库 API

在 React 18 中,我们和三方库作者合作,定义了一些新的 API,以满足三方库在 concurrent 模式下特定场景的诉求。比如 styles 管理、外部状态管理、可访问性(accessibility)等场景。

为了支持 React 18,一些三方库可能需要用到下面的 API:

useId 是一个新的 Hook,支持在客户端和服务端生成唯一的 ID,同时避免 hydration 的不兼容。它可以解决在 React 17 。 及更低版本一直存在的问题。在 React 18 中,这个问题尤为重要,因为流式 SSR 返回的 HTML 片段是无序的。更多信息可见 Intent to Ship: useId[8]。useSyncExternalStore是一个新的 Hook,允许外部状态管理器,强制立即同步更新,以支持并发读取。这个新的 API 推荐用于所有 。 React 外部状态管理库。详情见 useSyncExternalStore overview post[9]、useSyncExternalStore API details[10]。useInsertionEffect是一个新的 Hook,它可以解决 CSS-in-JS 库在渲染中动态注入样式的性能问题。除非你已经构建了一个 CSS-in-JS 库,否则我们不希望你使用它。这个 Hook 执行时机在 DOM 生成之后,Layout Effect 执行之前。更多信息可见 Library Upgrade Guide for style[11]。

React 18还为 concurrent 渲染引入了新的 API,例如 startTransition 和 useDeferredValue,在即将发布的稳定版本中会分享更多相关内容。

严格模式 Strict Mode

未来,我们希望添加一个功能,允许 React 保存组件的状态,但移除 UI 部分。比如在返回旧的页面时,React 立即恢复之前的内容。为此,React 将使用之前保留的状态重新加载组件。

这个功能会给 React 项目带来非常好的体验,但要求组件支持 state 不变的情况下,组件多次卸载和重载。

为了检查出不合适的组件写法,React 18 在开发模式渲染组件时,会自动执行一次卸载,再重新加载的行为,以便检查组件是否支持 state 不变,组件卸载重载的场景。

在以前,React 加载组件的逻辑为:

* React mounts the component.

* Layout effects are created.

* Effect effects are created.

在 React 18 严格模式的开发环境,React 会模拟卸载并重载组件:

* React mounts the component.

* Layout effects are created.

* Effect effects are created.

* React simulates unmounting the component.

* Layout effects are destroyed.

* Effects are destroyed.

* React simulates mounting the component with the previous state.

* Layout effect setup code runs

* Effect setup code runs

更多信息可见:Adding Strict Effects to Strict Mode[12] 、How to Support Strict Effects[13]。

配置测试环境

当你第一次在测试用例中使用 createRoot时候,你会看到以下警告:

The current testing environment is not configured to support act(…)。

为了修复这个问题,你需要在执行用例之前设置 globalThis.IS_REACT_ACT_ENVIRONMENT为 true。

// In your test setup file

globalThis.IS_REACT_ACT_ENVIRONMENT = true;

这个标记告诉 React,它在一个类似单元测试的环境中运行。如果你忘了使用 act,React 将打印一些有用的警告。你也可以将标志设置为 false 来告诉 React 不需要 act。这对于模拟浏览器环境的端到端测试很有用。当然,我们希望测试库会自动为您加上这个配置。例如,下一个版本的 React Testing Library 内置了对 React 18 的支持,无需任何额外配置。

更多信息可见:More background on the the act testing API and related changes[14]。

移除了 IE 支持

在此版本中,React 将放弃对 Internet Explorer 的支持。我们进行此更改是因为 React 18 中引入的新功能是基于现代浏览器开发的,部分能力在 IE 上是不支持的,比如 microtasks。

如果您需要支持 Internet Explorer,我们建议您继续使用 React 17。

其它变更移除“setState on unmounted component” 警告[15]。Susponse 不再强制需要 fallback 属性[16]。组件支持 render undefined[17]。废弃 renderSubtreeIntoContainer[18]。严格模式不再忽略自动二次渲染组件的 log[19]。参考资料

[1]How to Upgrade to the React 18 Release Candidate: https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html。

[2]React Conf: https://reactjs.org/blog/2021/12/17/react-conf-2021-recap.html。

[3]https://reactjs.org/link/switch-to-createroot: https://reactjs.org/link/switch-to-createroot。

[4]Replacing render with createRoot: https://github.com/reactwg/react-18/discussions/5。

[5]Upgrading to React 18 on the server: https://github.com/reactwg/react-18/discussions/22。

[6]New Suspense SSR Architecture in React 18: https://github.com/reactwg/react-18/discussions/37。

[7]Automatic batching for fewer renders in React 18: https://github.com/reactwg/react-18/discussions/21。

[8]Intent to Ship: useId: https://github.com/reactwg/react-18/discussions/111。

[9]useSyncExternalStore overview post: https://github.com/reactwg/react-18/discussions/70。

[10]useSyncExternalStore API details: https://github.com/reactwg/react-18/discussions/86。

[11]Library Upgrade Guide for style: https://github.com/reactwg/react-18/discussions/110。

[12]Adding Strict Effects to Strict Mode: https://github.com/reactwg/react-18/discussions/19。

[13]How to Support Strict Effects: https://github.com/reactwg/react-18/discussions/18。

[14]More background on the the act testing API and related changes: https://github.com/reactwg/react-18/discussions/102。

[15]移除“setState on unmounted component” 警告: https://github.com/reactwg/react-18/discussions/82。

[16]Susponse 不再强制需要 fallback 属性: https://github.com/reactwg/react-18/discussions/72。

[17]组件支持 render undefined: https://github.com/reactwg/react-18/discussions/75。

[18]废弃 renderSubtreeIntoContainer: https://github.com/facebook/react/pull/23355。

[19]严格模式不再忽略自动二次渲染组件的 log: https://github.com/reactwg/react-18/discussions/96。

    热门排行

    友情链接