React官宣v18更新内容

1,010 阅读3分钟

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

原文:reactjs.org/blog/2021/0…

React团队今日官宣了下一个大版本v18的核心内容包括:

本次大版本更新与v17类似,没有对原有接口的修改,应该可以放心地无痛升级。

目前可以通过@alpha标签安装尝鲜(不推荐哈哈):

npm install react@alpha react-dom@alpha

预估几个月后能见到公开测试版吧。有兴趣的同学可以尝试加入他们的工作组与大神们一起帮助v18正式版早日发布。

接下来我们看一下几个大功能的内容:

状态批量更新

状态批量更新其实不新鲜。 v18之前早就存在,只是因为某些原因,像v17中选择只将在React接手的事件处理回调中触发的一系列状态变化合并。比如一下例子中的setCountsetFlag

function App() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  function handleClick() {
    setCount(c => c + 1); // Does not re-render yet
    setFlag(f => !f); // Does not re-render yet
    // React will only re-render once at the end (that's batching!)
  }

  return (
    <div>
      <button onClick={handleClick}>Next</button>
      <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
    </div>
  );
}

但如果这些setState又被包了一层,在Promise、setTimeout等中触发合并就不起作用了了。

v18解决了这个痛点,所有你想得到的事件回调里的状态更新都可以自动合并哟!

不过以防万一我们遇到奇怪的问题想避免自动合并,可以使用ReactDOM.flushSync()接口:

mport { flushSync } from 'react-dom'; // Note: react-dom, not react

function handleClick() {
  flushSync(() => {
    setCounter(c => c + 1);
  });
  // React has updated the DOM by now
  flushSync(() => {
    setFlag(f => !f);
  });
  // React has updated the DOM by now
}

更多细节请看:github.com/reactwg/rea…

startTransition接口

这个新接口主要优化的是由状态变化引发大规模更新导致应用反应延迟。它将被“标”为“过渡”(transition)的状态更新作为低优先级可以被打断的任务处理,确保其他用户交互得以继续。

标志的方法也是通过一个回调:

import { startTransition } from 'react';

// Urgent: Show what was typed
setInputValue(input);

// Mark any state updates inside as transitions
startTransition(() => {
  // Transition: Show the results
  setSearchQuery(input);
});

另外,还提供了一个useTransition勾子用于提示“过渡”的状态变化。比如在更新完成之前可以像这样友好地显示个加载图标啥的:

import { useTransition } from 'react';

export default MyComponent() {
	const [isPending, startTransition] = useTransition();
  return isPending
    ? <Spinner />
    : <div>需要显示的内容</div>;
}

更多细节请看:github.com/reactwg/rea…

流式服务器渲染

服务器渲染的重大革新来啦!服务器等所有数据到到位生成完整HTML再发送到前端的噩梦终于有所进展。

在v16中提出的“Hydration”机制虽然能够让服务器渲染一部分剩余的交给客户端继续用以加速渲染的同时能让客户端恢复交互的能力,但这种方法有个致命的缺陷——必须等所有相关的代码在客户端加载完毕才能进行。

v18中通过应用潜伏已久的<Suspense>组件,React.lazy接口加新的react-dom/server接口pipeToNodeWritable实现在服务器渲染的背景下局部更新。

它的使用方式也非常简单,只需要将这些低优先级或者预期加载较慢的组件用<Suspense>包起来就好了,与React.lazy的用法雷同:

<Layout>
  <Banner />
  <Suspense fallback={<Spinner />}>
    <LowPriorityComponent />
  </Suspense>
</Layout>

但是这不能解决上述“Hydration”的问题。所以Dan强调,这需要配合代码分离即利用React.lazy以及打包工具把代码分块加载才更好使。

React.lazy<Suspense>在v18之前的SSR中并不支持,需要在SSR中去掉才能让UI得以显示。那v18之后就可以放心大胆地使用了!用户也可以更快地跟页面交互。

最后还有个小优化。如果用户尝试与还在Hydrate的部分交互,React会尝试提升它的优先级,让用户可以更快使用。

更多细节请看:github.com/reactwg/rea…