当前位置:首页 > 文章列表 > 文章 > 前端 > React useTransition 区分交互更新与后台渲染

React useTransition 区分交互更新与后台渲染

来源:17golang原创 2026-10-04 00:11:07 0浏览 收藏
热门推荐
漫画APP
动画内容聚合,热门资源快捷查看
立即下载

我第一次把 useTransition 加进一个搜索列表时,犯的错误很直接:把输入框的 setQuery 也包进了 startTransition。结果并没有得到“更顺滑的输入”,反而把必须立即反映到文本框里的状态当成了可延后的更新。

正确区分只有一句话:输入值、按下状态、焦点等直接反馈用户操作的状态应当同步更新;筛选大列表、切换重页面、展示可被新交互打断的内容更新,才适合标记为 Transition。useTransition 不会让 JavaScript 自动进入后台线程,它改变的是 React 安排状态更新和渲染工作的优先级。

React 官方说明:https://react.dev/reference/react/useTransition

判断标准不是“这段代码耗时吗”,而是“这次状态更新能否被更紧急的交互打断”。不能打断的输入反馈保持普通更新;可以重新开始的内容渲染才交给 Transition。

一、我为什么会把 useTransition 用错

当时的页面有一个受控搜索框,下面是数量较多的结果组件。输入一个字符会同时更新输入值、重新过滤数据并渲染列表。我看到输入出现停顿,第一反应是把整个 onChange 放进 startTransition,以为回调会“稍后执行”。

但 React 官方文档明确说明,传给 startTransition 的函数会立即调用;在这个调用期间同步安排的状态更新会被标记为 Transition。它不是 setTimeout,也不会延迟普通 JavaScript 计算。更重要的是,Transition 更新不能用于控制文本输入,因为受控输入需要在变化事件后同步反映新值。

更新对象用户期待推荐方式
输入框 value、选中状态、焦点反馈操作后立即可见普通 setState
大列表筛选、重组件切换可稍后完成,可被新操作打断startTransition 标记更新
过渡中的局部提示立即告诉用户内容仍在更新isPending
无法直接控制的派生值允许显示旧值并在后台追上考虑 useDeferredValue

二、把一个输入动作拆成两类状态更新

我后来保留了两个状态:query 专门控制输入框,必须同步更新;filterQuery 专门驱动较重的列表渲染,可以在 Transition 中更新。这样用户每次键入都会立即看到字符,而列表允许暂时保持旧结果,随后再追上最新条件。

React 输入状态、Transition 状态与列表渲染的静态关系说明图
图1:onChange 同时连接即时输入状态和 Transition 更新,isPending 只负责局部反馈;这是原创静态说明图,不是运行截图。
import { useMemo, useState, useTransition } from 'react';

export default function SearchPanel({ items }) {
  const [query, setQuery] = useState('');
  const [filterQuery, setFilterQuery] = useState('');
  const [isPending, startTransition] = useTransition();

  const filteredItems = useMemo(() => {
    // 重列表只依赖可延后的筛选条件
    const keyword = filterQuery.trim().toLowerCase();
    return items.filter((item) =>
      item.name.toLowerCase().includes(keyword)
    );
  }, [items, filterQuery]);

  function handleChange(event) {
    const nextQuery = event.target.value;

    // 受控输入必须立即更新,不能放进 Transition
    setQuery(nextQuery);

    startTransition(() => {
      // 只把驱动重列表的状态标记为非阻塞更新
      setFilterQuery(nextQuery);
    });
  }

  return (
    
{/* pending 只做轻量反馈,不遮住仍可阅读的旧列表 */} {isPending && 正在更新结果…}
); }

这里的关键不是复制两个状态,而是明确它们代表不同承诺:query 承诺“用户输入什么,文本框立刻显示什么”;filterQuery 承诺“结果最终追上最新输入,但中间可以被更新的输入打断”。如果列表很轻,不会影响交互,那么完全没有必要引入第二个状态和 Transition。

三、startTransition 标记的是更新,不是任务队列

这是最容易被 API 名称误导的地方。startTransition 的回调会立即执行,React 只会把回调执行期间同步触发的状态更新标记为非阻塞更新。重型循环、复杂正则或大对象转换仍然运行在当前 JavaScript 线程上;如果这些计算本身就阻塞事件循环,单独加 Transition 并不能把它们搬到 Web Worker。

Transition 渲染可以被其他更新打断。比如列表正在根据旧输入重新渲染时,用户又输入一个字符,React 可以先处理新的输入状态,再重新开始列表渲染。这种“可丢弃并重来”的特性,才是它适合筛选结果、切换标签和页面导航的原因。

function selectTab(nextTab) {
  // 回调现在就执行,但 setTab 会被标记为 Transition 更新
  startTransition(() => {
    setTab(nextTab);
  });
}

function runHeavyCalculation() {
  // 这段同步计算不会因为包进 startTransition 就进入后台线程
  const result = calculateLargeDataset();

  startTransition(() => {
    // 只有状态更新及其后续 React 渲染采用 Transition 优先级
    setResult(result);
  });
}

对我来说,一个实用判断是:如果卡顿发生在 React 提交新状态后的大量组件渲染,Transition 可能有帮助;如果卡顿发生在事件处理函数里的同步计算,先拆计算、缓存结果、分块处理或使用 Worker,别把 startTransition 当线程 API。

四、isPending 适合局部反馈,不适合封锁页面

useTransition 返回的第一个值 isPending 表示 Transition 仍在进行。它最适合放在触发区域附近:让标签文字变淡、显示“正在更新结果”,或者给结果容器加轻微透明度。因为 Transition 的目标就是维持页面可交互,如果一 pending 就覆盖整页、禁用所有控件,反而抵消了它的价值。

我倾向于只禁用会导致重复提交且无法安全重入的按钮,不禁用搜索输入和其他导航入口。对列表搜索,保留旧内容并给出轻量提示,比清空列表再显示大号加载动画稳定得多。

五、哪些代码不能直接放进 Transition

React 受控输入、异步边界与 Suspense 显示策略的静态边界说明图
图2:受控输入保持同步,await 后的更新需要重新标记,Transition 可避免已显示内容被整体 fallback 替换;这是原创静态说明图。

1. 受控文本输入的状态

把 setQuery 放进 Transition 会违背受控输入需要同步更新的要求。正确做法是同步更新输入值,再用另一个状态承载可延后的渲染条件;或者在只有一个源状态时,把 useDeferredValue 用在消费该值的重组件上。

2. 定时器里的状态更新

如果 setState 发生在 setTimeout 中,它已经不在原来的 startTransition 调用期间,不会自动保留 Transition 标记。要在定时器回调里再次调用 startTransition。

3. await 之后的状态更新

按照 React 当前官方文档中的限制,异步请求完成后、await 之后的状态更新需要再次包裹 startTransition。此外,多次异步 Action 的完成顺序并不天然等于触发顺序;涉及保存、下单或数量更新时,要使用能处理顺序的更高层抽象,或者自己实现取消、序列号和队列逻辑。

function saveSelection(nextId) {
  startTransition(async () => {
    // 网络请求可以处在 Action 中,但返回顺序仍需业务层负责
    const saved = await updateSelection(nextId);

    startTransition(() => {
      // 当前限制下,await 之后的状态更新需要再次标记
      setSelectedId(saved.id);
    });
  });
}

六、和 Suspense 一起使用时发生了什么

当一次普通更新让已经显示内容的 Suspense 边界再次挂起时,边界可能切回 fallback,页面会出现明显跳变。把更新标记为 Transition 后,React 会尽量保留已经显示的内容,而不是立刻用加载占位替换它。

但这个能力有边界:Transition 只会等待到足以避免隐藏已经展示的内容,新出现的嵌套 Suspense 边界仍可以立即显示自己的 fallback。它也不会让所有数据请求自动支持 Suspense;数据源或框架仍需提供相应集成。

七、useTransition、startTransition 和 useDeferredValue 怎么选

场景更合适的 API原因
组件内发起更新,并需要 pending 状态useTransition同时获得 isPending 与 startTransition
组件外的数据层发起状态更新startTransition不是 Hook,但不提供 pending 标志
无法控制状态更新位置,只能延后消费值useDeferredValue让派生视图在后台追上最新值
控制文本输入本身普通 setState输入反馈必须同步
同步计算阻塞事件循环拆分、缓存或 WorkerTransition 不会创建后台线程

常见问题

用了 useTransition,列表为什么还是慢?

Transition 优先保证紧急交互能插队,不承诺减少列表的总计算量。仍要检查不必要的重复渲染、键值稳定性、派生计算缓存、虚拟列表和组件粒度。它改善的是响应过程,不是自动优化所有代码。

isPending 为 true 时应该清空旧结果吗?

通常不建议。保留旧结果并显示轻量 pending 状态,可以让用户继续理解页面上下文。只有旧内容会造成错误操作或语义误导时,才考虑局部禁用或替换。

每个 setState 都可以包 startTransition 吗?

语法上可以标记很多更新,但语义上不应该。只有可中断、可重启、允许稍后呈现的内容更新才适合。输入、按压、拖拽位置等直接交互反馈应保持紧急更新。

useTransition 会让网络请求更快吗?

不会。它可以协调请求期间的状态和界面反馈,但不会缩短网络耗时,也不会自动解决响应乱序。请求缓存、取消、重试和顺序控制仍是独立问题。

我现在判断是否使用 useTransition,先问两个问题:用户刚做的动作是否必须立刻反映?后续内容渲染是否允许被下一次动作打断?前者用普通状态更新,后者才用 Transition。把这条边界守住,代码通常比“哪里慢就包哪里”更清晰,交互也更稳定。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
90fps画质产品站联系方式和备案信息怎么看?入口身份核对说明90fps画质产品站联系方式和备案信息怎么看?入口身份核对说明
上一篇
90fps画质产品站联系方式和备案信息怎么看?入口身份核对说明
mifun乐园适合哪些用户?动漫观看与社区交流定位说明
下一篇
mifun乐园适合哪些用户?动漫观看与社区交流定位说明
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    318次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    374次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    371次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    337次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    162次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码