React 第二十三节 useTransition Hook 的使用注意事项详解
文章内容 基于 React 18+ ,如有错误,欢迎批评指正;
一、概述:
useTransition
是一个在不阻塞UI渲染的情况下更新数据状态
,它会降低当前视图的渲染优先级,而优先执行视图中其它用户交互操作,比如 Tab切换、搜索加载等
二、特点:
1、可以保持当前UI的响应性
2、可以区分队列任务的紧急优先级别
3、可以提供加载指示器
4、不会阻塞用户的交互操作
三、基本用法
const [isPending, startTransition] = useTransition()
useTransition()
不接收任何参数,
返回参数:
a、isPending
: 告诉用户是否存在需要处理的transition;
b、startTransition
: 一个函数,可以将状态标记为 transtion
,不返回任何值,并且传入的函数必须是**同步【React 18】**的【React 19 支持异步】,不能在里面执行 setTimeout/setInterval 等异步操作;
如:
startTransition(() => {
// 这里是一个函数
setActivatedBar()
})
四、页签切换
比如在一个页签里面有大量数据需加载渲染,此时该页面的渲染必然会耗费很多时间;当切换至其它tab时,必然会导致页面出现卡顿现象,而出现点击下一个页签没有反应的假死现象;
假设 TabB
组件中有 100000条数据需要重组并渲染出来;
export default function TabB() {
let data = []
for(let i=0;i<100000;i++){
data.push({
title: `标题${i+1}`,
id: i,
content: `内容:${String(Math.random() * 100 )}`
})
}
return (
<div>
<ul>
{
data.map(itm => <li key={itm.id}>{itm.title}</li>)
}
</ul>
</div>
)
}
MyTransition
组件
当我们不使用 useTransition
时,tab之间的切换时页面会出现假死现象;
当使用 useTransition
时,即使当前 组件 TabB 在渲染过程中,我们依然可以切换下一个tab
import { useTransition, useState } from 'react'
import TabA from './tabA'
import TabB from './tabB'
import TabC from './tabC'
import './index.scss'
export default function MyTransition() {
const [activated, setActivated] = useState('A')
const [isPending, startTransition] = useTransition()
function handleTab(nextTab) {
startTransition(() => {
setActivated(nextTab)
})
}
return (
<div className='transition-box'>
<div className='nav-box'>
<button onClick={() => handleTab('A')} className={activated === 'A' ? 'activate' : ''}>TabA</button>
<button onClick={() => handleTab('B')} className={activated === 'B' ? 'activate' : ''}>TabB</button>
<button onClick={() => handleTab('C')} className={activated === 'C' ? 'activate' : ''}>TabC</button>
</div>
<div >
{ activated === 'A' && <TabA></TabA> }
{ activated === 'B' && <TabB></TabB> }
{ activated === 'C' && <TabC></TabC> }
</div>
</div>
)
}
TabA 与 TabC 组件
export default function TabA() {
return (
<div>
This is the first content
</div>
)
}
export default function TabC() {
return (
<div>
this is tab C content
</div>
)
}
五、使用场景
1、搜索输入建议:用户连续输入时,延迟处理搜索逻辑。
2、路由切换:预加载下一页数据时保持当前页响应。
3、表单分步提交:后台处理提交逻辑时允许用户继续交互。
4、复杂渲染任务:如大型列表过滤、图表绘制。
六、注意事项:
1、被标记为 transition
的状态更新,会被其他状态更新打断,优先执行其他状态更新;
2、startTransition
的函数必须是同步执行的,【React 19 中支持异步执行】这时React 会立即执行该函数,并且会将该函数执行过程中的 所有状态 标记为 transition,
3、transition
的更新不用于控制文本输入;
4、被标记为 transition
的状态,更新是非阻塞的,只是相对于其他状态降低了更新优先级
5、useTransition
会导致两次重新渲染,而不是一次
6、避免滥用:仅对用户可感知的非紧急更新使用(如搜索建议、后台数据加载;避免对即时反馈的操作(如按钮点击、表单提交)使用
,否则会延迟必要反馈,破坏用户体验。
7、不要在 startTransition 中
执行网络请求、定时器等副作用;仅包裹状态更新,副作用应在 useEffect
或事件处理函数
中执行
8、状态更新需要独立:如果在 startTransition
中同时更新多个状态,React 可能无法正确批处理,需要将多个状态 包裹在一个对象中处理,或者使用 useReducer 管理复杂状态
9、与Suspense 结合时注意
:若在 startTransition
中触发了 Suspense
回退(如懒加载组件),过渡期间会显示 fallback UI
;可以通过 isPending
状态自定义加载提示,避免重复加载效果冲突
10、如果过渡任务过长时,isPending
会导致加载提示长时间显示,需要使用 useDeferredValue
或优化后端请求,减少延迟时间