我给你用最简单、最直白、面试必过、一看就懂 的方式,彻底讲透 React 的 useDeferredValue + useTransition!
一句话核心结论
这两个 React 18 新 Hook ,专门解决:
大量数据渲染、复杂计算 → 导致页面卡顿、输入框延迟 的问题!
它们的作用:
让高优先级操作(输入、点击)不卡顿,低优先级操作(大数据渲染、复杂计算)延后执行。
先看场景(你一定遇到过)
js
const [text, setText] = useState('')
const list = filterBigList(text) // 超级耗性能,2万条数据
return (
<>
<input value={text} onChange={(e) => setText(e.target.value)} />
<div>{list.map(item => <div>{item}</div>)}</div>
</>
)
问题:
输入框打字 → 触发大数据过滤 → 页面卡死、延迟、掉帧
原因:
输入和渲染是同步高优先级,一起执行,UI 被阻塞。
一、useTransition(最常用)
作用
把 非紧急、耗性能的更新 标记为 低优先级更新
高优先级(输入)可以插队,页面永远不卡!
核心 API
js
const [isPending, startTransition] = useTransition()
isPending:低优先级任务是否在等待(可展示 loading)startTransition:把里面的更新降级为低优先级
代码演示(立刻不卡)
js
const [text, setText] = useState('')
const [list, setList] = useState([])
const [isPending, startTransition] = useTransition()
const onChange = (e) => {
// 1. 高优先级:立即更新输入框
setText(e.target.value)
// 2. 低优先级:延迟执行大数据渲染
startTransition(() => {
setList(filterBigList(e.target.value))
})
}
效果
输入框永远流畅!
大数据列表延迟一点点,完全不影响体验
二、useDeferredValue
作用
延迟一个值 ,等主线程空闲了,再更新这个值
适合:值来自父组件、无法用 startTransition 包裹
核心 API
js
const deferredValue = useDeferredValue(value)
代码演示
js
const [text, setText] = useState('')
// 让 text 延迟更新
const deferredText = useDeferredValue(text)
// 只有 deferredText 变了才执行耗性能操作
const list = useMemo(() => {
return filterBigList(deferredText)
}, [deferredText])
效果
和 useTransition 一模一样 !
输入流畅,大数据延迟渲染
三、两者区别(超级好记)
| 方式 | 用法 | 适用场景 |
|---|---|---|
| useTransition | 包裹 setState |
自己控制更新的地方 |
| useDeferredValue | 包裹一个值 | 子组件、无法控制 setState |
一句话区分:
- 控制更新函数 → useTransition
- 控制一个值 → useDeferredValue
四、底层原理(面试必问)
React 18 并发渲染 能力:
- 把更新分为 高优先级 / 低优先级
- 高优先级(输入、点击)可中断低优先级
- 低优先级渲染会被暂停、插队、恢复
- 保证 UI 永远流畅
五、超级总结(背这个就够)
useTransition
- 标记低优先级更新
- 不阻塞输入、点击
- 用法:
startTransition(() => { 耗性能更新 })
useDeferredValue
- 延迟一个值
- 等空闲再更新
- 用法:
const deferredVal = useDeferredValue(val)
共同目的
让耗性能的页面,不卡顿、不掉帧、保持流畅!
终极一句话
高优先级先走,低优先级等空闲 → 这就是 useTransition / useDeferredValue!