从工作原理入手理解React十:useDeferredValue

40 阅读1分钟

什么是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>
  )
}