React 18——[译文]新功能:startTransition

新功能:startTransition

概述

在React 18中,我们引入了一个新的API,即使你你的应用在大屏幕更新,也能保持更新。
这个新的API让你通过将特定的更新标记为 "transitions "来大幅改善用户互动。React将让你在状态转换时提供视觉反馈,并在转换发生时保持浏览器的响应。

Real world example: adding startTransition for slow renders

解决了什么

构建感觉流畅、响应迅速的应用程序并不总是容易的。有时,像点击一个按钮或在一个输入框中打字这样的小动作会导致屏幕上发生很多事情。这可能导致页面冻结或挂起,而所有的工作正在进行。

例如,考虑输入一个过滤数据列表的输入字段。你需要在状态中存储该字段的值,以便你能过滤数据并控制该输入字段的值。你的代码可能看起来像这样:

// Update the input value and search results
setSearchQuery(input);

在这里,每当用户输入一个字符,我们就更新输入值,并使用新的值来搜索列表并显示结果。对于大屏幕的更新,这可能会造成页面上的滞后,而所有的东西都会被渲染,使打字或其他互动感到缓慢和没有反应。即使列表不是太长,列表项本身也可能很复杂,每次按键都不同,可能没有明确的方法来优化它们的渲染。

从概念上讲,问题在于有两个不同的更新需要发生。第一个更新是一个紧急的更新,以改变输入字段的值,并有可能改变它周围的一些用户界面。第二个是不太紧急的更新,以显示搜索的结果。

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

// Not urgent: Show the results
setSearchQuery(input);

用户期望第一次更新是立即的,因为本地浏览器对这些互动的处理是快速的。但第二次更新可能会有点延迟。用户并不期望它立即完成,这很好,因为可能有很多工作要做。(事实上,开发者经常用debouncing等技术人为地延迟这种更新)。

在React 18之前,所有的更新都是紧急渲染的。这意味着上面的两个状态仍然会在同一时间被渲染,并且仍然会阻止用户看到他们互动的反馈,直到一切都渲染完毕。我们缺少的是一种告诉React哪些更新是紧急的,哪些不是。

startTransition做了什么

这个新的 startTransition API 赋予你了可以标记为 "transitions"的能力。

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);
});

被startTransition包裹的更新被当作非紧急事件来处理,如果有更紧急的更新,如点击或按键,则会被打断。如果一个过渡被用户打断(例如,连续输入多个字符),React会扔掉未完成的陈旧的渲染工作,只渲染最新的更新。

过渡让你保持大多数交互的敏捷性,即使它们导致了重大的UI变化。它们还可以让你避免浪费时间去渲染那些不再相关的内容。

startTransition是什么

我们把状态更新分为两类。

  • 紧急更新反映了直接的互动,如打字、点击、按压等等。
  • 过渡性更新将用户界面从一个视图过渡到另一个。

像打字、点击或按压这样的紧急更新,需要立即做出反应,以符合我们对物理物体行为方式的直觉。否则他们就会感到 "不对劲"。然而,转换是不同的,因为用户并不期望在屏幕上看到每个中间值。

例如,当你在一个下拉菜单中选择一个过滤器时,你希望过滤器按钮本身在你点击时能立即做出反应。然而,实际结果可能会单独过渡。一个小的延迟将是难以察觉的,而且往往是预期的。而且,如果你在结果渲染完成之前再次改变过滤器,你只关心看到最新的结果。

在一个典型的React应用中,大多数更新在概念上是过渡更新。但出于向后兼容的原因,过渡是选择进入的。默认情况下,React 18仍然将更新作为紧急处理,你可以通过将更新包装成startTransition来标记为过渡。

startTransition与setTimeout的不同

一个常用的解决上述问题的方法是外面包一层setTimeout定时器

// Show what you typed
setInputValue(input);

// Show the results
setTimeout(() => {
  setSearchQuery(input);
}, 0);

这将使第二次更新推迟到第一次更新呈现之后。Throttling和debouncing是这种技术的常见变种。

一个重要的区别是,startTransition不像setTimeout那样被安排在稍后的时间。它是立即执行的。传递给startTransition的函数是同步运行的,但其中的任何更新都被标记为 "过渡"。React将在以后处理更新时使用这些信息来决定如何渲染更新。这意味着我们开始渲染更新的时间比用超时包装的要早。在一个快速的设备上,两个更新之间会有很小的延迟。在慢速设备上,延迟会更大,但用户界面会保持响应。

另一个重要的区别是,在setTimeout内的大屏幕更新仍然会锁定页面,只是在超时后。如果用户在超时发生时仍在打字或与页面互动,他们仍将被阻止与页面互动。但是标有startTransition的状态更新是可以中断的,所以它们不会锁住页面。它们让浏览器在渲染不同组件之间的小空隙中处理事件。如果用户的输入发生了变化,React就不必继续渲染用户不再感兴趣的东西了。

最后,因为setTimeout只是简单地延迟更新,显示加载指示器需要编写异步代码,这通常是很脆的。有了过渡,React可以为你跟踪待定状态,根据过渡的当前状态进行更新,并让你能够在用户等待时显示加载反馈。

当处理transition 时,应该做什么

作为一个最佳实践,你会希望通知用户在后台有工作发生。为此,我们提供了一个带有isPending标志的Hook,用于过渡期。

import { useTransition } from 'react';


const [isPending, startTransition] = useTransition();

isPending的值在transition 为true,允许你在用户等待时显示一个加载提示。

{isPending && <Spinner />}

你包裹在transition中的状态更新不一定要在同一个组件中产生。例如,搜索输入中的旋转器可以反映重新渲染搜索结果的进度。

为什么不写更快的代码

编写更快的代码和避免不必要的重现仍是优化性能的好方法。转场是对这一点的补充。它们可以让你在重大的视觉变化中保持UI的响应性--例如,在显示一个新屏幕时。这很难用现有的策略来优化。即使在没有不必要的重新渲染的情况下,过渡仍然提供了比把每一次更新都视为紧急的更好的用户体验。

什么时候去使用startTransition

你可以使用startTransition来包装任何你想转移到后台的更新。通常情况下,这些类型的更新分为两类。

  • 缓慢的渲染。这些更新需要时间,因为React需要执行大量的工作,以便过渡到UI来显示结果。下面是一个真实世界的演示,添加startTransition以在昂贵的重新渲染过程中保持应用的响应性。
  • 网络速度慢。这些更新需要时间,因为React正在等待来自网络的一些数据。这个用例与Suspense紧密结合。
    我们很快会再次发帖,用具体的例子介绍这些用例中的每一个。如果你有任何问题,请告诉我们!

原文

New feature: startTransition

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容