React18新hook:useDeferredValue

useDeferredValue 的基础用法

useDeferredValue 可以让你延迟更新 UI 的某些部分

用法如下:

jsx 复制代码
const deferredValue = useDeferredValue(someValue);

其中someValue是你想要延迟的值,它可以是任何类型。

deferredValue的渲染有两种情况:

  1. 在初始渲染时deferredValue的值将与someValue的值相同。
  2. 在UI更新期间 ,因为deferredValue的优先级较低,即使并发模式下deferredValue已在后台更新,React也会先使用旧值渲染,当其它高优先级的状态更新完成,才会把deferredValue新值渲染出来。

useDeferredValue 应用示例

在新内容加载期间显示旧内容

比如,在搜索时,我们可能会配合 Suspense 组件,当发起搜索请求时,展示 fallback 的内容,请求完毕时,再显示最新的结果。

jsx 复制代码
import { Suspense, useState } from 'react';
import SearchResults from './SearchResults.js';

export default function App() {
  const [query, setQuery] = useState('');
  return (
    <>
      <label>
        Search albums:
        <input value={query} onChange={e => setQuery(e.target.value)} />
      </label>
      <Suspense fallback={<h2>Loading...</h2>}>
        <SearchResults query={query} />
      </Suspense>
    </>
  );
}

像这样,有一个 loading 效果:

然而,我们可以通过 useDeferredValue,在搜索时,延迟更新的结果也就是在发送搜索请求时,不展示 loading,旧数据依然展示(下面的例子我们给旧数据置灰),当请求完毕时,再去渲染最新的数据

jsx 复制代码
import { Suspense, useState, useDeferredValue } from 'react';
import SearchResults from './SearchResults.js';

export default function App() {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  return (
    <>
      <label>
        Search albums:
        <input value={query} onChange={e => setQuery(e.target.value)} />
      </label>
      <div style={{
          opacity: isStale ? 0.5 : 1,
          transition: isStale ? 'opacity 0.2s 0.2s linear' : 'opacity 0s 0s linear'
        }}>
          <SearchResults query={deferredQuery} />
      </div>
    </>
  );
}
  • 当搜索 a 时:
  • 然后再搜索 ab 时,旧数据置灰,当请求成功时,再渲染最新的数据

延迟渲染 UI 的某些部分

你还可以将 useDeferredValue 作为性能优化的手段。当你的 UI 某个部分重新渲染很慢、没有简单的优化方法,同时你又希望避免它阻塞其他 UI 的渲染时,使用 useDeferredValue 很有帮助。

想象一下,你有一个文本框和一个组件(例如图表或长列表),在每次按键时都会重新渲染:

jsx 复制代码
// app.jsx
import { useState, useDeferredValue } from 'react';
import SlowList from './SlowList.js';

export default function App() {
  const [text, setText] = useState('');
  return (
    <>
      <input value={text} onChange={e => setText(e.target.value)} />
      <SlowList text={text} />
    </>
  );
}

每次你输入的时候,SlowList 都会接受到新的 props,然后重新渲染,就会导致卡顿,然而,我们可以通过 useDeferredValue 去做延迟渲染

jsx 复制代码
// app.jsx
import { useState, useDeferredValue } from 'react';
import SlowList from './SlowList.js';

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} />
    </>
  );
}

// SlowList.jsx
import { memo } from 'react';

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>
  )
}

export default SlowList;

效果如下:

  • 在输入停止前,不会 rerender

  • 输入停止后,再渲染

useDeferredValue 和 节流、防抖的区别

从上面的学习可以看出来,useDeferredValue在某些场景下是可以替换掉节流防抖

防抖与节流的局限性

  • 这两种方法都是为了控制函数的执行频率,但它们是阻塞的,可能会导致不流畅的用户体验。

useDeferredValue的优势

  • 它与React深度集成,可以适应用户的设备。如果设备性能好,延迟的重新渲染会很快完成;如果设备性能差,重新渲染会相应地延迟。
  • 它不需要选择固定的延迟,与防抖和节流不同。
  • useDeferredValue执行的重新渲染是可中断的。这意味着在React重新渲染期间,如果发生了其他更新,React会中断当前的渲染并处理新的更新。

适用场景

  • 如果要优化的工作不是在渲染期间进行的,例如减少网络请求,那么防抖和节流仍然是有用的。
  • 如果优化的目标是和渲染有关的,建议使用useDeferredValue
相关推荐
screct_demo2 小时前
詳細講一下在RN(ReactNative)中,6個比較常用的組件以及詳細的用法
javascript·react native·react.js
光头程序员11 小时前
grid 布局react组件可以循数据自定义渲染某个数据 ,或插入某些数据在某个索引下
javascript·react.js·ecmascript
limit for me11 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者11 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架
VillanelleS14 小时前
React进阶之高阶组件HOC、react hooks、自定义hooks
前端·react.js·前端框架
傻小胖15 小时前
React 中hooks之useInsertionEffect用法总结
前端·javascript·react.js
flying robot1 天前
React的响应式
前端·javascript·react.js
GISer_Jing1 天前
React+AntDesign实现类似Chatgpt交互界面
前端·javascript·react.js·前端框架
智界工具库2 天前
【探索前端技术之 React Three.js—— 简单的人脸动捕与 3D 模型表情同步应用】
前端·javascript·react.js
我是前端小学生2 天前
我们应该在什么场景下使用 useMemo 和 useCallback ?
react.js