You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React 18使用useTransition()时大列表输入仍卡顿的原因

useTransition() 未生效导致输入卡顿的核心原因

useTransition 的作用是标记低优先级状态更新,让输入、点击这类紧急交互的更新优先响应,但它不会减少实际需要执行的渲染工作量,也不会自动跳过非必要的组件重渲染,你的代码存在几个关键问题,导致优先级调度完全没发挥作用:

  • 未对大体积列表组件做记忆化隔离:输入触发setNeedle这个高优先级更新时,App组件会重渲染,由于startTransition触发时isPending会同步更新为高优先级状态,PeopleList组件接收到的isLoading属性发生变化,会跟着一起重渲染,直接同步执行2万条列表项的遍历、颜色计算、React元素生成逻辑,这个耗时约0.5秒的长任务直接阻塞主线程,输入框自然会卡顿。
  • 存在不必要的重复计算:每次渲染列表项时,都会对每条名称执行一次toLowerCase(),2万条数据每次渲染都会重复执行这个操作,额外增加了计算耗时。
  • 全量渲染2万条DOM节点:useTransition只能调整更新的优先级,不会拆分或减少实际的DOM渲染、diff工作量。2万条节点全量渲染的成本本身就很高,哪怕优先级调度生效,长渲染任务依然会阻塞交互。
  • 容易忽略的前提:如果项目入口没有使用React 18的createRootAPI,而是沿用旧版的ReactDOM.render,所有并发特性(包括useTransition)都不会生效,行为和React 17完全一致。
对应优化方案
  • 确认入口使用createRoot挂载应用,开启React 18并发能力:
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(<App />);
  • 用React.memo包裹PeopleList组件,仅当people/highlight/isLoading三个属性实际变化时才重渲染列表,隔离输入框的高优先级重渲染逻辑,避免输入时带着大列表一起重跑。
  • 提前预处理名称数据,导入JSON后一次性把所有名称转成小写,避免渲染时重复计算:
const processedPeople = people.map(name => ({
  original: name,
  lowerCase: name.toLowerCase()
}));

后续匹配时直接用预计算的lowerCase字段做includes判断即可。

  • 针对2万条规模的列表,必须搭配虚拟列表方案,只渲染视口内可见的数十条条目,把实际渲染的DOM节点数量从2万降到几十,从根源上降低渲染开销。useTransition只能在渲染工作量本身可控的前提下优化交互响应顺序,无法替代虚拟列表解决大列表渲染的性能问题。

内容的提问来源于stack exchange,提问作者Robo Robok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 08:33:20