react 的 useTransition 、useDeferredValue
useTransition
用于 管理状态更新的过渡(pending)状态
,避免因高优先级任务(如用户输入)被低优先级任务(如数据获取或复杂计算)阻塞而导致的界面卡顿。
它特别适用于,需要 区分紧急更新和非紧急更新 的场景。
useTransition 的核心作用
-
标记非紧急更新:
1、允许某些状态更新(如:数据获取、复杂计算)被标记为“过渡”(startTransition),让 React 知道这些更新可以延迟执行。
2、紧急更新(如用户输入、动画)会优先执行,避免界面卡顿。 -
显示加载状态:
在过渡期间,可以显示一个加载指示器(如骨架屏、旋转图标),提升用户体验。 -
避免不必要的渲染:
如果过渡更新被更高优先级的更新打断,React 会丢弃未完成的过渡更新,避免浪费资源。
基本用法
import { useState, useTransition } from 'react'function App() {const [ isPending, startTransition ] = useTransition()const [ list, setList ] = useState([])const [ inputValue, setInputValue ] = useState('')const handleInputChange = (e) => {setInputValue(e.target.value) // 紧急更新(用户输入)}const handleSearch = () => {startTransition(() => {// 模拟一个耗时的数据获取操作const newList = fetchData(inputValue) // 非紧急更新(数据获取)setList(newList)})}return (<div><inputtype="text"value={inputValue}onChange={handleInputChange}/><button onClick={handleSearch}>Search</button>{isPending && <p>Loading...</p>} {/* 显示加载状态 */}<ul>{list.map((item) => (<li key={item.id}>{item.name}</li>))}</ul></div>) // end-return
}// 模拟数据获取
function fetchData(query) {// 假设这是一个耗时操作(如 API 请求)return Array.from({ length: 1000 }, (_, i) => ({id: i,name: `${query} Item ${i}`,}))
}
- 解析
-
useTransition
返回一个数组:
isPending
:布尔值,表示是否有未完成的过渡更新。
startTransition
:函数,用于标记某个状态更新为“过渡”。 -
紧急更新 vs. 过渡更新:
紧急更新
(如 setInputValue)会立即执行,不会被延迟。
过渡更新
(如 setList)会被标记为低优先级,React 会在空闲时执行。 -
isPending 的作用
:
在过渡期间,isPending 为 true,可以用于显示加载状态(如 Loading…)。 -
startTransition 的使用
:
将耗时操作包裹在startTransition
中,告诉 React 这是非紧急更新。
总之
useTransition
是 React 18 提供的优化工具,用于 区分紧急和非紧急更新,避免界面卡顿。isPending
可以用于显示加载状态,提升用户体验。startTransition
用于标记非紧急更新,让 React 知道可以延迟执行。
如果你的应用中有 耗时操作(如:数据获取、复杂计算),并且希望 避免阻塞用户交互,useTransition
是一个非常好的选择! 🚀
useDeferredValue
useDeferredValue
的核心作用
-
延迟低优先级更新:
- 当某个状态(如:输入框的值)变化时,React 会优先处理高优先级任务(如:用户输入),而延迟处理低优先级任务(如:列表渲染)。
- 避免因列表渲染导致输入框卡顿。
-
自动管理优先级:
- 不需要手动调用
startTransition
,useDeferredValue
会自动决定何时延迟更新。
- 不需要手动调用
-
避免不必要的渲染:
- 如果输入值快速变化(如:用户连续输入),React 会丢弃未完成的低优先级更新,避免浪费资源。
基本用法
import { useState, useDeferredValue } from 'react'function SearchResults() {const [ query, setQuery ] = useState('')const deferredQuery = useDeferredValue(query) // 延迟更新后的值const [ list, setList ] = useState([])// 模拟数据获取(耗时操作)const fetchData = (q) => {return Array.from({ length: 1000 }, (_, i) => ({id: i,name: `${q} Item ${i}`,}))}// 当 deferredQuery 变化时,更新列表// (但不会阻塞用户输入)React.useEffect(() => {setList(fetchData(deferredQuery))}, [deferredQuery])return (<div><inputtype="text"value={query}onChange={(e) => setQuery(e.target.value)}placeholder="Search..."/><ul>{list.map((item) => (<li key={item.id}>{item.name}</li>))}</ul></div>) // end-return
}
-
useDeferredValue
返回一个延迟的值:deferredQuery
是query
的延迟版本,React 会在空闲时更新它。- 用户输入(
query
变化)是紧急更新,会立即响应。 - 列表渲染(基于
deferredQuery
)是低优先级更新,会延迟执行。
-
自动优化性能:
- 如果用户快速输入,React 会丢弃未完成的
deferredQuery
更新,避免浪费资源。 - 只有当用户停止输入或输入速度变慢时,才会执行低优先级更新。
- 如果用户快速输入,React 会丢弃未完成的
-
适用场景:
- 搜索框 + 动态列表:用户输入时,列表渲染不会阻塞输入。
- 过滤/排序大数据:用户调整筛选条件时,列表更新不会卡顿。
优化后的代码示例(带加载状态)
import { useState, useDeferredValue, useEffect } from 'react'function SearchResults() {const [ query, setQuery ] = useState('')const deferredQuery = useDeferredValue(query)const [ list, setList ] = useState([])const [ isLoading, setIsLoading ] = useState(false)useEffect(() => {setIsLoading(true)const timer = setTimeout(() => {setList(Array.from({ length: 1000 }, (_, i) => ({id: i,name: `${deferredQuery} Item ${i}`,})))setIsLoading(false)}, 300)return () => clearTimeout(timer) // 清理未完成的更新}, [deferredQuery])return (<div><inputtype="text"value={query}onChange={(e) => setQuery(e.target.value)} />{isLoading && <p>Loading...</p>}<ul>{list.map((item) => (<li key={item.id}>{item.name}</li>))}</ul></div>) // end-return
}
总结
useDeferredValue
是 React 18 提供的优化工具,用于 延迟低优先级状态更新,避免阻塞用户交互。- 适用场景:输入框关联的动态内容(如搜索建议、过滤列表)。
- 优势:
- 自动管理优先级,无需手动调用
startTransition
。 - 避免因低优先级任务导致界面卡顿。
- 提升用户体验,特别是在输入场景下。
- 自动管理优先级,无需手动调用
如果你的应用中有 输入框 + 动态列表 的交互,useDeferredValue
是一个非常合适的优化方案! 🚀