useDeferredValue

useDeferredValue的实际功能可能跟它的字面意思不是很一样,它提供的并不是一种 State,而是用来延迟 UI 的更新的。在组件中使用useDeferredValue可以获取指定值的延迟版本,通常与useState组合使用。useDeferredvalue打的返回值在组件初始渲染时与原始值相同,但是在组件更新的时候,React 会首先尝试使用旧值做组件的重新渲染,然后在后台使用新值做另一个重新渲染。

React 在后台会使用Object.is来比较旧值和新值,如果两者不同,那么 React 将会安排一个后台渲染,但这个后台渲染是可以被中断的。如果在 React 进行后台渲染期间,useDeferredValue接收到了另一个新值,那么之前的后台渲染就将会被中断。这个操作十分类似于常见的数据防抖操作,但是useDeferredValue的防抖时间阈值非常的小,所以不要将其做作为防抖方法使用。

useDeferredValue的主要功能还是用来在新内容加载期间展示用于替代的旧内容,改善 UI 的显示效果。需要注意的是,useDeferredValue的后台渲染不会触发任何useEffect定义的副作用,所有的副作用会在 UI 更新后执行。

useDeferredValue最典型的使用案例就是延迟更新数据列表,例如以下示例。

function DeferredList() {
  const [quest, setQuery] = useState([]);
  const deferredQuery = useDeferredValue(query);

  return (
    <>
      <div>
        <label>Search Keyword: </label>
        <input value={query} onChange={(e) => setQuery(e.target.value)} />
      </div>
      <Suspense fallback={<span>Loading...</span>}>
        <SearchResults query={deferredQuery} />
      </Suspense>
    </>
  );
}

以上示例将useDeferredValue<Suspense>组件搭配使用了,这可以达到在<SearchResults>组件未完成数据加载的时候,先展示旧数据和加载提示的效果。

如果需要判断当前展示的数据是新值还是旧值,在以上示例中可以使用query !== deferredQuery来判断。如果它们两个不相等,那么当前展示的就依旧是旧值,否则就是新值了。