问题
在深入探讨 useTransition
之前,让我们首先了解一下它旨在解决的问题。这将帮助我们更好地理解其核心价值。
想象一个应用程序,它配备了一个搜索框以及一个能展示大量用户信息的列表。用户可以通过在搜索框中输入用户名来筛选并查看相关用户。
下面是实现代码:
App.js slowItem.js index.js styles.css sandbox.config.json
import { useState } from 'react' ;
import SlowItem from './slowItem' ;
export default function App ( ) {
const [ searchValue , setSearchValue ] = useState ( '' )
const [ filtered , setFiltered ] = useState ( [ ] )
const handleSearch = ( { target : { value } } ) => {
setSearchValue ( value )
setFiltered ( Array ( 500 ) .fill ( value ) )
}
return (
< div >
< h2 > User Finder Without Transiton</ h2 >
< input
type ="text"
placeholder ='Search for an user...'
autoFocus
value ={ searchValue }
onChange ={ handleSearch }
/>
< ul className ='wrapper' >
{
filtered .map ( ( item , index ) => (
< SlowItem key ={ index } text ={ item } />
) )
}
</ ul >
</ div >
)
}
在我们的应用程序中,用户信息是通过<SlowItem />
组件来呈现的。这个组件在渲染过程中故意暂停了1毫秒
,以模拟一种极度耗时的渲染场景。此外,每次进行搜索操作,都会产生500
条用户信息。
上面完全实现了功能需求,但存在几点明显的性能问题:
快速输入时,输入框会卡顿和延迟
用户列表更新同样存在延迟
造成这些问题的原因是:当用户在输入框中快速输入时,每敲击一个字符都会触发一次组件的重新渲染。鉴于每次渲染都相当耗时,这就意味着每次搜索操作都可能引发大量的计算和数据处理活动。在这种情形下,用户体验可能会大受影响。用户可能会经历明显的延迟或卡顿,尤其是在他们尝试快速输入搜索关键词以便获得即时反馈时。
解决方案
正是在这样的背景下,useTransition
派上了用场。它允许开发者将这些潜在的高成本更新标记为低优先级 任务,从而确保应用程序在处理这些更新时仍然对用户输入保持响应。通过这种方式
useTransition
帮助我们在不阻塞 UI 的情况下更新状态。
这有助于改善用户体验,特别是在涉及大量数据处理或复杂计算的应用程序中。
语法
让我们看一下useTransition
的用法:
const [ startTransition , isPending ] = useTransition ( ) ;
useTransition
会返回一个包含两个元素的数组:
isPending
: 布尔值,当startTransition
函数执行时返回true
,执行完成返回false
startTransition
将回调函数作为参数的函数。此回调函数应包含与非紧急状态更新相关的代码
使用
下面我们看下使用useTransition
优化后的版本, 注意三处标注📌的地方。在该版本中我们能明显感觉到性能的提升:
在快速键入时,输入框不会卡顿。
在快速键入时,因为isPending
一直处于true
,所以只会渲染Loading...
,而不是500条用户信息。
停止输入时,isPending
变为false
,此时才会真正去渲染500条用户信息。
App.js slowItem.js index.js styles.css sandbox.config.json
import { useState , useTransition } from 'react' ;
import SlowItem from './slowItem' ;
export default function App ( ) {
const [ searchValue , setSearchValue ] = useState ( '' )
const [ filtered , setFiltered ] = useState ( [ ] )
const [ isPending , startTransition ] = useTransition ( ) ;
const handleSearch = ( { target : { value } } ) => {
setSearchValue ( value )
startTransition ( ( ) => {
setFiltered ( Array ( 500 ) .fill ( value ) )
} )
}
return (
< div >
< h2 > User Finder With Transiton</ h2 >
< input
type ="text"
placeholder ='Search for an user...'
autoFocus
value ={ searchValue }
onChange ={ handleSearch }
/>
< ul className ='wrapper' >
{
isPending ? (
< div > Loading...</ div >
) : (
filtered .map ( ( item , index ) => (
< SlowItem key ={ index } text ={ item } />
) )
)
}
</ ul >
</ div >
)
}