你不知道的React系列(二十四)useDeferredValue

60 阅读1分钟

本文正在参加「金石计划」

const [deferredValue] = useDeferredValue(value);
  • 频繁更新组件进行节流

    • deferredValue 首次渲返回 value,再次渲染中首先返回原先数据,然后返回新的数据

    • value 应为原始数据或者是在渲染之外的对象

  • deferredValue 接收不同的数据时, 依赖它的渲染逻辑只会使用最新的数据进行渲染

  • <Suspense> 一块使用, 不会出现 fallback

  • 自身不会阻碍网络请求

  • useDeferredValue 不是固定的,渲染和事件更新都会影响

  • useDeferredValue 引发的 background re-rende 不会触发 Effect 执行,它会等到数据加载完UI更新以后

  • 通常是组件内部使用

新数据加载时候展示旧数据

import { Suspense, useState } 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>
      <Suspense fallback={<h2>Loading...</h2>}>
        <SearchResults query={deferredQuery} />
      </Suspense>
    </>
  );
}

添加效果

import { Suspense, useState, useDeferredValue } from 'react';
import SearchResults from './SearchResults.js';

export default function App() {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  const isStale = query !== deferredQuery;
  return (
    <>
      <label>
        Search albums:
        <input value={query} onChange={e => setQuery(e.target.value)} />
      </label>
      <Suspense fallback={<h2>Loading...</h2>}>
        <div style={{
          opacity: isStale ? 0.5 : 1,
          transition: isStale ? 'opacity 0.2s 0.2s linear' : 'opacity 0s 0s linear'
        }}>
          <SearchResults query={deferredQuery} />
        </div>
      </Suspense>
    </>
  );
}

延迟部分 UI 重新渲染

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

缓存节流子组件

  • useDeferredValue只会节流你传给它的值
  • 使用React.memo或者React.useMemo阻止子组件频繁更新
function Typeahead() {
  const query = useSearchQuery('');
  const deferredQuery = useDeferredValue(query);

  // Memoizing tells React to only re-render when deferredQuery changes,
  // not when query changes.
  const suggestions = useMemo(() =>
    <SearchSuggestions query={deferredQuery} />,
    [deferredQuery]
  );

  return (
    <>
      <SearchInput query={query} />
      <Suspense fallback="Loading results...">
        {suggestions}
      </Suspense>
    </>
  );
}