React 18 带给我们的惊喜

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列

这篇文章发布于3.28日,3.29日 react 18 发布。

1、前言

React 18 的 alpha 版已经发布有段时间了,之前学习后由于没有开发实践结合去思考,对 React 18 的意义认识并不深刻。前段时间做了一些老旧项目迁移,发现复杂项目下每次渲染都要精心调整,否则就会有麻烦的性能或体验瑕疵,而 React 内部渲染顺序和优先级很难调整,就导致总体体验差了点意思。回顾了 React 18 的三个新特性,有种久旱逢甘雨的欣喜。

团队内部推行了 React hook,好处就不在这里赘述了,也陆续收到了一些负面反馈。其一就是 React hook 更加趋向面向数据实体进行拆分,而一个动作需要多个数据实体协作,例如一个 Modal Form 需要 visible 和 data 两个数据项协作,但是这两个数据项的变更会触发两次渲染结算,增加性能开销。

作者之前遇到过复杂 Form 表单下,初次渲染由于数据项过于复杂导致无限次 render 的 bug。在这个 case 中,核心的冲突就是在数据项复杂度提升的同时,React Diff 的性能就遇到了“伪瓶颈”。这里不是说 React Diff 性能差,仅仅想表达它的高性能需要更高的设计理念和实践经验,这也是相对于 Vue 等更加易学的框架而言,总的来说上限高下限也低。而 React 18 的变化让我看到了 React 团队正在关注这一部分,并且给予了更好的解决方案。

闲聊到此为止,进入正题,给大家介绍下 React 18 的四个重要新特性:

  • Automatic batching

  • Concurrent APIS

  • SSR for Suspense

  • New Render API

2、Automatic batching

在 React 中使用 setState 来进行 dispatch 组件 State 变化,当 setState 在组件被调用后,并不会立即触发重新渲染。React 会执行全部事件处理函数,然后触发一个单独的 re-render,合并所有更新。这里举个简单例子:

const [count, setCount] = useState(0);function increment() {// setCount(count + 1)// 使用无状态函数进行优化,避免多次 re-rendersetCount(c => c + 1);
}function handleClick() {increment();increment();increment();
}

最终 React 会将更新函数放到一个队列里,然后合并队列触发 setCount (3) 的 re-render,这就是 batching 的含义。

这样既可以减少程序数据状态存在中间值导致的不稳定性,也可以提升渲染性能。但是可惜的是在 React 18 之前,如果在回调函数的异步调用中,执行 setState,由于丢失了上下文,无法做合并处理,所以每次 setState 调用都会触发一次 re-render。

function handleClick() {// React 18 以前的版本(/*...*/).then(() => {setCount((c) => c + 1); // 立刻重渲染setFlag((f) => !f); // 立刻重渲染});
}

而 React 18 带来变化便是,任何情况下都可以合并渲染了!

如果你希望在 React 18 的 setState 后立即执行重新渲染, 只需要使用 flushSync 包裹即可。

function handleClick() {// React 18+fetch(/*...*/).then(() => {ReactDOM.flushSync(() => {setCount((c) => c + 1); // 立刻重渲染setFlag((f) => !f); // 立刻重渲染});});
}

回归到实际开发中,Automatic batching 机制让我们有能力对渲染顺序和节奏进行一些基础的把控。例如在 Canvas 画布编辑场景中,我们可以加载完主节点框架之后立刻进行渲染,而每个节点的内容则可以进行合并渲染,尽可能加快用户看到可编辑页面的时间,同时避免 http 异步函数引起的频繁渲染的性能开销。

cd12778142653bb75949754ab0be5edd.png

3、Concurrent APIS

在官方视频中明确指出了 React 18 中并不存在 Concurrent Mode,只有用于并发渲染的并发新特性。开发者希望能够在 Web Platform 引入并发渲染,来实现多个渲染任务的并行渲染,其中 Suspense 就是基于此诞生的。

React 18 提供了三个新的 API 支持这一并发特性,分别是:

  • startTransition()

  • useDeferredValue()

  • useTransition()

由于 useTransition 的官方文档并未放出来,这里就仅仅介绍另外两种 API。

3.1 startTransition()

import { startTransition } from "react";// 紧急更新:
setInputValue(input);// 标记回调函数内的更新为非紧急更新:
startTransition(() => {setSearchQuery(input);
});

简单来说,被 startTransition 包裹的 setState 触发的渲染被标记为不紧急渲染,意味着他们可以被其他紧急渲染所抢占。这种渲染优先级的调整手段可以帮助我们解决各种性能伪瓶颈,提升用户体验。

3.2 useDeferredValue()

这个 hook 适用于设置延迟值,参考官方演示视频来看。

function Page() {const [filters, mergeFilter] = useMergeState(defaultFilters);const deferedFilters = React.useDeferedValue(filters);return (<Fragment><Filters filters={filters} ><List filters={deferedFilters} ></Fragment>);
}

useDeferedValue () 会将 List 组件的渲染变得更加平滑,深层次来看则是 defered value 引起的渲染则会被标记为不紧急渲染,会被 filters 引起的渲染进行抢占,进而达到用户快速输入搜索等场景下页面抖动或者卡顿问题。

4、SSR for Suspense

早在 2018 年,React 就推出了 Suspense 的基础版本。

e728a70775d315ae4e266cccec742bee.png

它可以在客户端动态加载代码(React.lazy),配合 Suspense 组件实现数据拉取和状态控制的关注点分离(当子组件未加载完成时,父组件填充 fallback 声明的组件),但是并不能在服务器端进行加载。

<Suspense fallback={<Skeleton />}><Header /><Suspense fallback={<ListPlaceholder />}><ListLayout /></Suspense>
</Suspense>

React 的开发者对 Suspense 的期望并不仅仅止步于此,他们认为 Suspense 拓展了我们对组件的概念。在 React 18 中,Suspense 可以运行在服务器端,Server Rendering 的性能不需要受制于性能最差的组件(木桶效应)。

在 React 18 之前,Server Rendering 的流程是服务器端请求所有数据,然后发送 HTML 到客户端或者说浏览器,然后由客户端的 hydrate 内容,每个环节必须按部就班的执行。当 Suspense 可以在服务器端使用之后,一旦某个组件加载慢,就可以将 fallback 的内容传输到客户端(例如下图中的 loading 态),保证用户尽可能早的可进行交互。

c79ce29ccb0d46daa83c7f4b643c4cc8.png

更加优秀的部分则是,hydrate 是可以通过用户的行为来调整优先级的,例如上图中 Profile 组件和正在 Loading 的评论组件同时处于 Suspense 的流程中,此时用户点击评论组件,React 将会优先 hydrate 评论组件,尽可能优先满足用户交互体验。

回归到代码实现细节,整体框架上服务器和客户端的连接必然趋向于持续性的长链接,因此 res.send 需要变成 res.socket,pipeToNodeWritable 替换 renderToString 并且配合 Suspense 即可(官方例子)。

5、New Render API

新的更加友好的语义化 render 方式。

const container = document.getElementById("app");// 旧 render API
ReactDOM.render(<App />, container);// 新 createRoot API
const root = ReactDOM.createRoot(container);
root.render(<App />);

Client 端提供了新 水合 Hydrate API。

const root = ReactDOM.hydrateRoot(container, <App tab="home" />);

以及 新 useId () API 来为组件生成唯一 ID。

由于 Suspense 和 并发渲染在 React 18 的大规模使用,一些具有 External stores 的 API,比如全局变量、document 对象如何在并发场景下保证一致性呢?如果无法保证一致性,在并发渲染过程中可能会导致组件展示的不一致。

ef3976f1f0bb14f9f07b70973e5e4708.png

为了解决这个问题,React 18 提供了 useSyncExternalStore() 这个 hook,来保证获取 External stores 的一致性。

useSyncExternalStore(// 注册回调函数subscribe: (callback) => Unsubscribe,// 获取快照函数getSnapshot: () => state
) => state

具体使用方式参考:

ec7f01a1a3a89fc5a562207c20ca58ba.png

6、React 未来展望

在官方视频中,开发者们也对未来版本的内容进行介绍。

Support for Data Fetching API

由于 Suspense 的大规模应用,其数据获取变得更加定制化,目前常见的有 Relay、React Query 等。React 官方也希望将这一部分纳入到 React 的 API 中。

Server Component

组件不仅可以通过网络读取数据、也可以后台数据层直接读取服务数据,将大大减少服务器端向客户端传输的代码量,和同构模式十分类似。

React 18 in React Native

2022 年 React 18 将和 React Native 一起发布,跨平台构建的史诗级更新,RN 并发的一些老大难将得到解决。

7、结语

结合起来看,React 18 关注点在于更快的性能、用户交互响应效率和跨平台构建,其设计理念处处包含了中断与抢占概念。React 18 给我们提供了一些从应用构建视角下的手段,例如:

  1. 在 Client 端随时中断的框架设计,第一优先级渲染用户最关注的 UI 交互模块。

  2. 从后端到前端 “顺滑” 的管道式 SSR,并将 hydration 过程按需化,且支持被更高优先级用户交互行为打断,第一优先水合用户正在交互的部分。

作为一名前端开发,十分期待 React 18 的到来。

db23d15eac47d11a6d09a998c531d163.gif

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》20余篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经坚持写了8年,点击查看年度总结。
同时,最近组织了源码共读活动,帮助3000+前端人学会看源码。公众号愿景:帮助5年内前端人走向前列。

f665561e27eada368c1325fe044180a4.png

扫码加我微信 ruochuan02、拉你进源码共读

今日话题

略。分享、收藏、点赞、在看我的文章就是对我最大的支持~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/274780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

建模心法(2)——迈出建模第一步

原文地址&#xff1a;http://www.cnblogs.com/1-2-3/archive/2008/08/04/model-method-part1.html 原文作者&#xff1a;景春雷 一错再错的这故事才精彩 ——朴树 《我爱你再见》摘要 即使读了再多的书、跟过再多的项目&#xff0c;…

Web:你知道我这十几年是怎么过来的吗?!

大家好&#xff0c;我是若川。持续组织了8个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列1989 …

设计师更高效_如何丢掉我的工作使我成为一名更好的设计师

设计师更高效I lost my job a few times early on in my design career. In the process of getting back up after a job loss, it has made me a better designer not only in terms of hard skills but the soft skills required to be more resilient and empathetic, whic…

【ASP.NET】登陆成功后如何跳转到上一个页面

当用户浏览网页的时候会在某个地方需要用户登陆才能继续浏览&#xff0c;用户登陆之后会自动跳转到刚刚浏览的页面。这个步骤是怎么实现的呢&#xff1f;net小伙在查阅相关资料实践之后终于明白了&#xff0c;其实很简单&#xff0c;先分享给大家吧。 当用户在浏览一个页面的时…

4月,诚邀你参加源码共读,学会看源码,打开新世界!开阔视野

大家好&#xff0c;我是若川。很多关注我的新朋友可能不知道我组织了源码共读活动~也有很多人不知道我是谁。有人以为我是80后。有人以为我是全职自媒体等等。若川的 2021 年度总结&#xff0c;弹指之间 这篇文章写了我是16年毕业的&#xff0c;或许有些启发。源码共读按照从易…

bt709和srgb_选择用于多用途视频编辑和色彩校正的显示器— sRGB,DCI-P3,REC 709

bt709和srgb**Note from the author: if you enjoy this article, please follow me or this publication for more video production and marketing related content.****作者注&#xff1a;如果您喜欢本文&#xff0c;请关注我或此出版物以获取更多与视频制作和营销相关的内容…

超4000人参加源码共读,喊你来一起学习成长~打开新世界

大家好&#xff0c;我是若川。很多关注我的新朋友可能不知道我组织了源码共读活动~也有很多人不知道我是谁。有人以为我是80后。有人以为我是全职自媒体等等。若川的 2021 年度总结&#xff0c;弹指之间 这篇文章写了我是16年毕业的&#xff0c;或许有些启发。源码共读按照从易…

figma设计_如何在Figma中构建设计入门套件(第二部分)

figma设计Figma教程 (Figma Tutorial) With this short, but informative Tutorial Series I aim to show you how to build the solid foundations of a powerful, and versatile Design Starter Kit, enabling you to start your next project in Figma faster than ever bef…

GitHub 最受欢迎的Top 20 JavaScript 项目

大家好&#xff0c;我是若川。持续组织了8个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列今天来…

java反编译,eclipse支持插件

http://java.decompiler.free.fr/?qjdeclipse 按照说明 在eclipse更新插件就可以。 这样 在一些 闭源的jar文件&#xff0c;你也可以看到 大致的源码。&#xff08;公司 知道如何 加密混淆 java代码或class文件&#xff0c;居然无法使用jd-gui浏览源码&#xff09; 而&#xf…

unity vr 交互_基于手动的VR / MR交互,用于删除实体

unity vr 交互Deleting an entity or closing an application is one of the most ubiquitous operations performed in any application. It is necessary for the organization of the data. On the computer, there are multiple ways to delete a file like cmd delete, d…

手把手带你走进Babel的编译世界

大家好&#xff0c;我是若川。持续组织了8个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列前言谈…

同态加密应用_重新设计具有同态性的银行应用

同态加密应用Catering user preference is undoubtedly a never-ending task. End of the day, it takes all sorts to make a world. For that reason, it is deemed important to design with the accent of communicating core business value, and resolving user needs wi…

(字节/华为/美团)前端面经记录冷冷清清的金三银四

大家好&#xff0c;我是若川。持续组织了8个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列从毕业…

netflix_Netflix播放按钮剖析

netflixWe will develop a play pause button similar to the one the Netflix video player has.我们将开发一个类似于Netflix视频播放器的播放暂停按钮。 Since Swift has replaced Objective-C as the default development language for iOS, the same will apply to Swift…

TypeScript 终极初学者指南

大家好&#xff0c;我是若川。持续组织了8个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列在过去…

标记偏见_如何(巧妙地)扭曲视觉效果以支持您的偏见叙事

标记偏见Data is important — it is the logical justification for world-changing decisions. Unfortunately, arrays of numbers don’t tell as interpretable a story as a picture does, providing an insatiable need for data visualizations.数据很重要-这是改变世界…

高瓴投资,顶配创业团队,dora 诚招前端 / Flutter

dora 是一个可以跨越设计稿&#xff0c;直接生成应用的新一代设计工具。让任何 Creator 都能轻松构建个性化的网站和应用&#xff0c;无需编写一行代码。通过自主研发的全新技术&#xff0c;我们为用户打造了完全自由度的设计与开发体验&#xff0c;足以满足任何复杂场景的个性…

猎鹰spacex_SpaceX:简单,美观的界面是未来

猎鹰spacex重点 (Top highlight)A photo has been floating around the internet showing how the interior of the new Dragon spacecraft differs from the Space Shuttle. The difference is staggering, but not entirely suprprising. After all the Shuttle started oper…

开发交接文档_为开发人员创造更好的设计交接体验

开发交接文档It’s 2020. We’re supposed to have flying cars and space travel. We should at least have our process for design handoff nailed down at this point.现在是2020年。我们应该有飞行汽车和太空旅行。 在这一点上&#xff0c;我们至少应该确定我们的设计移交…