[译]试用React 18 Alpha 版本

这是我参与更文挑战的第14天,活动详情查看:更文挑战

本文翻译自 《Trying Out React 18 Alpha Release》

image.png

React 团队最近新发布了 React 18 的 alpha 版本,主要是提升了并发性能。

新版本有以下几点尝试:

  • 新的 ReactDOM.createRoot() 替换了原来的 ReactDOM.render()
  • 通过批处理改进来减少渲染次数;
  • <Suspense>组件支持了 SSR
  • 新增了 startTransition API,用于非紧急状态下的懒加载。

想要使用React 18 alpha 版本,可以通过 NPM 或 Yarn 安装 @alpha版本:

npm install react@alpha react-dom@alpha
# 或者
yarn add react@alpha react-dom@alpha
复制代码

如果你使用了 Create React App 来创建项目,你可能会收到 could not resolve dependency 的报错,这是由于 react-scripts 引起的。

Could not resolve dependency:
peer react@">= 16" from react-scripts@4.0.3
复制代码

可以使用 --force 来同时更新 reactreact-dom:

npm install react@alpha react-dom@alpha --force
复制代码

本教程将会帮你了解 React 18 Alpha 中的新特性。

ReactDOM.createRoot() API 解释

ReactDOM.createRoot() 方法代替了之前的 ReactDOM.render() 方法,来作为应用程序入口。

这个方法是用来阻止 React 18 更新导致应用程序崩溃,新方法还允许创建一个新应用,并与React 17 对比性能。

以下是使用 createRoot() 的示例:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
const container = document.getElementById('root');
// Create a root.
const root = ReactDOM.createRoot(container);
// Render the top component to the root.
root.render(<App />);
复制代码

当你更新到 React 18 后,仍然继续使用 .render()方法来创建入口的话,就会收到控制台的报错日志,提醒你使用新的 Root API。

只有使用了 createRoot() 方法,才能使用React 18 的功能。

想了解更多可以看这里: createRoot discussion page here

渲染自动批处理的优化

我们都知道,React 是一个通过状态改变来重新渲染 UI 的库。

例如,当你把任意状态值从 false 改为 true,React 都会通过重新渲染 UI 来「做出反应」,根据你写的代码来调整屏幕显示内容。

下面的 <App> 组件会根据color状态值来渲染黑色或红色的标题:

function App() {
  const [color, setColor] = useState(false);
  function handleClick() {
    setColor((color) => !color); // react re-renders
  }
  return (
    <div>
      <button onClick={handleClick}>Change color</button>
      <h1 style={{ color: color ? "red" : "black" }}>Hello</h1>
    </div>
  );
}
复制代码

每次执行setColor(), React都会立即更新UI。

批处理就是把多个状态的更新,分组合并为一次UI渲染中的机制。通过这种机制,你可以避免不必要的渲染,并且优化渲染过程。

回到刚才的例子,当 handleClick() 执行的时候,我们添加另一个状态。

function App() {
  const [color, setColor] = useState(false);
  const [clickCount, setClickCount] = useState(0);
  
  function handleClick() {
    setColor((color) => !color);
    setClickCount((click) => click + 1);
  }
  return (
    <div>
      <button onClick={handleClick}>Change color</button>
      <h1 style={{ color: color ? "red" : "black" }}>
        Hello, your click count is {clickCount}
      </h1>
    </div>
  );
}
复制代码

如果没有批处理机制,handleClick() 执行的时候UI会更新两次,一次改变 color,另一次改变 clickCount。

但是批处理机制在 React 17 中执行得并不一致,当你在回调函数中去改变state 时就不会产生批处理。

例如,假设你在 setColor()setClickCount()之前先去远程请求数据,批处理不会生效,UI 还是会渲染两次。

function handleClick() {
  fetchUserData().then(() => {
    setCount(c => c + 1); // Causes a re-render!
    setFlag(f => !f); // Causes a re-render!
  });
}
function fetchUserDate(){
  // code omitted for brevity...
}
复制代码

setTimeout()中更新 state 也是一样的效果:

function handleClick() {
  setTimeout(() => {
    setColor((color) => !color);
    setClickCount((click) => click + 1);
  }, 1000);
}
复制代码

React 18 通过优化批处理机制解决了以上问题。

现在无论是在 Promise 、setTimeout、原生事件处理,还是之前没有支持的其他事件里,只要调用多个 state 的更新时,都会触发批处理。

关于这个机制的讨论可以看 这里

支持SSR

<Suspense>组件支持通过增加fallback组件,在代码加载完成前使用备用组件显示。

这里是 <Suspense>使用的例子:

<Suspense fallback={<LoadingSpinner />}>
  <UserProfile />
<Suspense />
复制代码

你可以在 React 文档里查看 <Suspense>的深度介绍。

在React 18 中, <Suspense>组件提供了对SSR的支持,这次更新允许你在 <Suspense>组件内包裹服务端渲染的组件。

任何一个服务端组件放在 <Suspense>中,加载的时候会显示 fallback参数指定的组件,加载完成后,React 会发送新的 HTML 来替换 fallback组件。

例如,你有<Article><Comments>两个组件:

<Layout>
  <Article />
  <Suspense fallback={<Spinner />}>
    <Comments />
  </Suspense>
</Layout>
复制代码

服务端渲染的时候,<Article>组件会被优先处理,<Comments>组件会被指定的备用组件<Spinner>替代。当<Comments>组件在服务端渲染完成,React会发送给浏览器替换掉<Spinner>组件。

深入了解 SSR 和 Suspense,你可以访问这里: GitHub discussion

startTransition API : 用于非紧急状态更新

startTransition是首次出现的新特性,它可以在应用需要大量计算能力来渲染UI时,仍然保持响应状态。

例如当你创建了一个筛选列表的输入框,状态更新时需要计算和显示匹配的内容。

你可能需要两个方法来处理: 一个处理输入值的变化,另一个处理筛选。

// Set the input value state
setInputValue(input);

// Set the search query input. Reflected later on the UI
setSearchQuery(input);
复制代码

当元素大量增加,筛选元素的计算量也会增加,这可能会使应用缓慢或者卡死。

为了缓解这个问题,React 允许你用 transitions 来标记某些更新。

Transition 更新被视为一个非紧急的更新,允许 React 优先处理紧急的更新。

回到之前的例子,搜索筛选的更新可以通过包裹在 startTransition中来实现延迟更新。

import { startTransition } from 'react';
// Urgent: Show what was typed
setInputValue(input);
// Mark any state updates inside as transitions
startTransition(() => {
  setSearchQuery(input);
});
复制代码

当更重要的更新被触发时,包裹在startTransition中的更新就会被中断。

上面的例子中,当用户不断输入字符时,搜索操作的 transition 更新就会被打断。这个特性可以优化React的重新渲染性能,以及减少对陈旧更新的不必要计算。

你可以在 此处 找到有关 startTransition API 的 更多信息。

结论

上面提到的一些特性在 React 18 介绍 中还没有被发布。(例如useDeferredValue<SuspenseList>

React 18 Alpha 给 React 带来了一些有趣的特性,提高了框架的并发能力。你可以安装reactreact-dom@alpha版本来尝试。

React 服务端组件 虽然还没有更新,但是新的并发功能,比如SSR支持Suspense组件和从服务端流式传输 HTML,可能都有助于以后实现服务端组件。

React 18 的发布时间表如下:

  • Alpha 版本用于收集反馈,并提供给 React 工作组使用(当前可用)
  • Beta 版本开放给所有人使用(至少在Alpha 版本发布后几个月)
  • RC(Release Candidate) 候选版本在 beta 版发布后数星期内发布
  • 稳定版将在RC版发布后数星期发布

感谢阅读此文,轻松地开始尝试 React 18 吧,不过应用越复杂,需要改动的地方可能会越多。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享