什么是useDeferredValue
useDeferredValue 是React18引入的一个新hook,用于返回一个延迟值来延迟更新某个区域,让紧急的更新优先于不紧急的更新先执行。
为什么需要useDeferredValue
上文中的Transition同样是将将更新标记为不紧急更新,通过这种机制来达到一定的性能优化和交互体验的效果。但是Transtion接收的action函数无法标记prop和自定义hook所产生的状态,用到这些状态的部分要实现延迟更新则要通过useDeferredValue来实现。
基本使用
useDeferredValue 接收一个值,返回该值的新副本,新副本会延迟更新。useDeferredValue 利用React的更新机制(状态改变重新渲染UI),通过返回一个延迟的值(状态更新之前的值),这样延时值是没有变化的,就规避掉需要延迟更新的部分更新,在React内部优先更新紧急的更新任务,在浏览器空闲时,会在内部处理延迟更新的部分。当延迟更新未完成,但页面再次发生紧急更新任务时,这个延时任务会被中断,直到浏览器再次空闲时恢复执行。
export default function App() {
const [text, setText] = useState('');
const deferredText = useDeferredValue(text);
return (
<>
<input value={text} onChange={e => setText(e.target.value)} />
<SlowList text={deferredText} />
</>
);
}
const SlowList = memo(function SlowList({ text }) {
// 仅打印一次。实际的减速是在 SlowItem 组件内部。
console.log('[ARTIFICIALLY SLOW] Rendering 250 <SlowItem />');
let items = [];
for (let i = 0; i < 250; i++) {
items.push(<SlowItem key={i} text={text} />);
}
return (
<ul className="items">
{items}
</ul>
);
});
function SlowItem({ text }) {
let startTime = performance.now();
while (performance.now() - startTime < 1) {
// 每个 item 暂停 1ms,模拟极其缓慢的代码
}
return (
<li className="item">
Text: {text}
</li>
)
}