如何升级到 React 18发布候选版

令人激动的事情出现了,近期React 官网发布了react@rc 版本,并且发布博客文章 《如何升级到 react18 RC 版本》 。文中提到了 RC 版本已经发布以及如何升级到新版本的要点. 同时鼓励大家升级尝试。

本文是一篇科普文,会介绍一些在官方文档中说明的一些要点,如果你想了解更加深入React 18 有哪些特性,可以阅读我们的往期文章。如果您想帮助我们测试 React 18,请按照本升级指南中的步骤并报告您遇到的任何问题,以便我们能够在稳定版发布之前修复这些问题。

如何安装react@rc 版本

yarn add react@rc react-dom@rc
或者
npm install react@rc react-dom@rc

重要 API变动

替换 ReactDOM.render 为 Root API

// Before
import { render } from 'react-dom';
const container = document.getElementById('app');
render(<App tab="home" />, container);
 
// After
import { createRoot } from 'react-dom/client';
const container = document.getElementById('app');
const root = createRoot(container);

React 18 提供了两个 root API,被称之为 Legacy Root API 和 New Root API:

  • Legacy Root API:是指之前版本的 root API ReactDOM.render,它将创建一个以 "legacy" 模式运行的 root,其工作方式与 React 17 完全相同。我们会给这个 API 添加一个警告,来说明它将要被弃用并建议切换到 New Root API。

  • New Root API:新的 root API 是 ReactDOM.createRoot。它可以在 React 18 中创建一个 root,并支持 React 18 中支持的所有新特性。

在 React 中,"root" 是一个指向顶层数据结构的指针,React 用它来跟踪要渲染的树。在 Legacy Root API 中,root 对用户来说是不透明的,因为我们将它附加到 DOM 元素上,通过 DOM 节点访问它,并没有将其暴露给用户:

我们更改这个 API 有以下几个原因。

  • 首先,这修复了 API 在运行更新时的一些人类工程学问题。如上所示,在 Legacy API 中,你需要多次将容器元素传递给 render,即使它从未更改过。这也意味着我们不需要将根元素存储在 DOM 节点上,尽管我们今天仍然这样做。

  • 其次,这一变化允许让我们可以移除 hydrate 方法并替换为 root 上的一个选项;删除渲染回调,这些回调在部分 hydration 中是没有意义的。

什么是 hydration ?

我们已经把 hydrate 函数移到了 hydrateRoot API 上。

before
import * as ReactDOM from 'react-dom';
import App from 'App';

const container = document.getElementById('app');

// Render with hydration.
ReactDOM.hydrate(<App tab="home" />, container);
after
import * as ReactDOM from 'react-dom';

import App from 'App';

const container = document.getElementById('app');

// Create *and* render a root with hydration.
const root = ReactDOM.hydrateRoot(container, <App tab="home" />);
// Unlike with createRoot, you don't need a separate root.render() call here

注意,与 createRoot 不同,hydrateRoot 接受原生 JSX 作为第二个参数。这是因为初始客户端渲染是特殊的,需要与服务器树匹配。

如果你想在 hydration 后再次更新 root,你可以将它保存到一个变量中,就像使用 createRoot 一样,然后调用 root.render():

import * as ReactDOM from 'react-dom';
import App from 'App';

const container = document.getElementById('app');

// Create *and* render a root with hydration.
const root = ReactDOM.hydrateRoot(container, <App tab="home" />);

// You can later update it.
root.render(<App tab="profile" />);

服务端渲染 API 的更新

在React@rc版本中,React 为了支持服务端的 Suspense 和SSR,改进了 react-dom/server,不支持 Suspense 的 Node.js 流式 API 将会被完全弃用:

  • renderToNodeStream 被弃用

  • 针对 Node 环境中的流媒体,使用:renderToPipeableStream。同时引入了一个新的 API renderToReadableStream,用于流式 SSR 和 Suspense,并为现代边缘运行环境提供支持,比如 Deno 和 Cloudflare workers:renderToString、renderToStaticMarkup 这两个 API 还可以继续用,但是对 Suspense 支持就不那么友好了。

最后,renderToStaticNodeStream这个 API 将继续使用,用于渲染电子邮件

Automatic Batching

由于架构设计问题,在 React 18 之前,React 只能在组件生命周期函数或合成事件函数中进行批处理。在默认情况下,Promise、setTimeout 以及异步回调是无法获得批处理的优化。

批处理是说 React 将多个状态更新合并到一个重新渲染中,以此来获得更好的性能。在 React 18 before,react 将一个事件中的多个 setState 合并为一个进行处理,在 promises、 setTimeout、和其他异步事件的更新没有合并。

// React 18 before

function handleClick() {
  setCount(c => c + 1);
  setFlag(f => !f);
  // 在合成事件中,享受批处理优化,只会重新渲染一次
}

setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // 不会进行批处理,会触发两次重新渲染
}, 1000);

// React 18 

function handleClick() {
  setCount(c => c + 1);
  setFlag(f => !f);
  // 只会重新渲染一次
}

setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // 只会重新渲染一次
}, 1000);

新的API的变化

  • useSyncExternalStore将替代useMutableSource 用于订阅外部源,允许外部存储通过强制同步更新来支持并发读取。这个新的 API 推荐用于任何与 React 外部状态集成的库

import {useSyncExternalStore} from 'react';

// 基础用法,getSnapshot返回一个缓存的值
const state = useSyncExternalStore(store.subscribe, store.getSnapshot);

// 根据数据字段,使用内联的getSnapshot返回缓存的数据
const selectedField = useSyncExternalStore(store.subscribe, () => store.getSnapshot().selectedField);
  • useId用于在客户端与服务端之间产生唯一ID,避免SSR hydrate时元素不匹配,这可以解决 React 17 以及更低版本的问题。

function Checkbox() {
  const id = useId();
  return (
    <>
      <label htmlFor={id}>Do you like React?</label>
      <input type="checkbox" name="react" id={id} />
    </>
  );
);
  • useInsertionEffect工作原理类似useLayoutEffect,区别在于回调执行时还不能访问ref中的DOM节点。它可以解决 CSS-in-JS 库在渲染中动态注入样式的性能问题。

function useCSS(rule) {
  useInsertionEffect(() => {
    if (!isInserted.has(rule)) {
      isInserted.add(rule);
      document.head.appendChild(getStyleForRule(rule));
    }
  });
  return rule;
}
function Component() {
  let className = useCSS(rule);
  return <div className={className} />;
}

更新严格模式 (Strict Mode)

未来,React期望添加一个这样的特性,允许 React 添加和删除 UI 部分,同时保留所有的状态。例如,当用户选项卡远离屏幕并返回时候,React 应该能够立即显示前一个屏幕。为此,React 将使用与前面相同的组件状态卸载和重新挂载树。

此特性将使 React 具有更好的开箱即用的性能,但是需要组件对多次挂载和销毁的效果具有弹性。多数效果不需要任何改变就可以工作,但有些效果假设它们只被安装或者销毁一次。

为了帮助表面这些问题,react 18 引入了一个新的开发-只检查严格模式。每当一个组件第一次挂载时,这个新的检查将自动卸载和重新挂载每个组件,恢复第二次挂载时以前的状态。

配置你的测试环境

为了解决 The current testing environment is not configured to support act(…)的警告,你可以设置

globalThis.IS_REACT_ACT_ENVIRONMENT = true;

设置完后,React将在类似单元测试的环境中运行,当然,如果测试库可以自动为你配置这个功能就太棒了。例如:下一个版本的 React Testing Library 内置了对 React 18的支持

不再支持 IE 浏览器

在本次版本中,React 不再对  Internet Explorer 进行支持,它会在2022年6月15日失去支持。React 之所以做出这个改变,是因为在 React 18 引入的新特性是使用现代浏览器的特性构建的,比如微任务等,这些特性在 IE 中无法充分填充与支持。

其他变化

  • 更新以删除“setState on unmounted component” 警告

  • Suspense不再需要fallbackprop 来捕捉

  • 组件现在可以渲染 undefined

  • 弃用 renderSubtreeIntoContainer

  • StrictMode 更新为默认情况下不会静默双重日志记录

如果大家想了解更多内容,欢迎查看 React 官方博客:https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html

源码

最后, 送人玫瑰,手留余香,觉得有收获的朋友可以点赞,关注一波 ,相关 文档资料 已上传至 React 中文社区交流群, 请关注公众号,点击菜单栏 入群学习,入群就送前端精选100本电子书 添加 入群小助手 后入群领取。陆续更新前端超硬核文章。

推荐阅读

(点击标题可跳转阅读)

[极客前沿]-你不知道的 React 18 新特性

[极客前沿]-写给前端的 K8s 上手指南

[极客前沿]-写给前端的Docker上手指南

[面试必问]-你不知道的 React Hooks 那些糟心事

[面试必问]-一文彻底搞懂 React 调度机制原理

[面试必问]-一文彻底搞懂 React 合成事件原理

[面试必问]-全网最简单的React Hooks源码解析

[面试必问]-一文掌握 Webpack 编译流程

[面试必问]-一文深度剖析 Axios 源码

[面试必问]-一文掌握JavaScript函数式编程重点

[面试必问]-阿里,网易,滴滴,头条等20家面试真题

[面试必问]-全网最全 React16.0-16.8 特性总结

[架构分享]- 微前端qiankun+docker+nginx自动化部署

[架构分享]-石墨文档 Websocket 百万长连接技术实践

[自我提升]-Javascript条件逻辑设计重构

[自我提升]-送给React开发者十九条性能优化建议

[自我提升]-页面可视化工具的前世今生

[大前端之路]-连前端都看得懂的《Nginx 入门指南》

[软实力提升]-金三银四,如何写一份面试官心中的简历

觉得本文对你有帮助?请分享给更多人

关注「React中文社区」加星标,每天进步

6112f562793fec5f2642b77fd5345c5f.png  

6e6d9a1e00ec672d784c1e2446ba1dbc.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值