You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中startTransition与useDeferredValue为何表现差异巨大?

React中useDeferredValue与自定义实现的渲染差异问题

我在代码库中大量使用useDeferredValue(),原本以为它能完全支持并发模式,但实际发现它并不会把渲染拆分为小块;而被startTransition包裹的setState触发的渲染会拆分成5ms的块。

在React DevTools中观察到:普通setState触发的渲染优先级为immediate,useDeferredValue或startTransition+setState触发的渲染优先级都是normal,所以我之前一直以为后两者的行为是一致的。

于是我尝试把所有useDeferredValue调用替换成自定义的useDeferredValue2:

function useDeferredValue2(val) {
  const [deferred, setDeferred] = useState(val);

  useEffect(() => {
    React.startTransition(() => {
      setDeferred(val);
    });
  }, [val]);

  return deferred;
}

替换后发现,useDeferredValue2触发的所有渲染都会拆分为5ms块,和原生useDeferredValue的差异很明显。那是不是原生useDeferredValue基本等同于下面这个useDeferredValue3?

function useDeferredValue3(val) {
  const [deferred, setDeferred] = useState(val);

  useEffect(() => {
    setDeferred(val);
  }, [val]);

  return deferred;
}

想请教:在React内部,useDeferredValue、useDeferredValue2和useDeferredValue3触发的渲染存在哪些差异?


三者的渲染行为差异

1. 原生useDeferredValue

  • 属于渲染阶段的同步延迟计算:当输入值val变化时,React会在当前渲染周期内直接计算并返回延迟值,不会触发额外的重渲染。
  • 它的“延迟”仅体现在优先级让步:如果有更高优先级的任务(比如用户输入),React会暂停这个低优先级的计算,优先处理高优先级任务;但一旦开始执行,会一次性完成渲染,不会拆分为5ms的块,这就是看不到分片的核心原因。
  • 优先级标记为normal,但属于渲染阶段的优先级,而非状态更新阶段的优先级。

2. useDeferredValue2(基于startTransition的自定义实现)

  • 触发额外的可中断并发更新:通过useEffect在渲染完成后,用startTransition包裹setDeferred,这会将这次状态更新标记为“可中断”的低优先级任务。
  • React会将渲染拆分为多个5ms的小块,利用浏览器空闲时间执行,一旦有更高优先级的任务(比如用户交互)就会暂停当前渲染,优先处理高优先级任务,这就是能看到渲染分片的原因。
  • 这里的normal优先级是状态更新的优先级,且带有并发可中断标记。

3. useDeferredValue3(基于useEffect的简单实现)

  • 本质是渲染完成后的普通同步更新:useEffect触发的setDeferred是一次普通的状态更新,优先级为normal但没有并发可中断标记。
  • React会一次性完成这次渲染,不会进行分片;如果此时有高优先级任务,必须等这次渲染完成后才能处理,无法中断。
  • 和原生useDeferredValue的核心区别:原生是渲染阶段同步计算值,无额外重渲染;它是渲染完成后触发额外重渲染,多一次渲染周期。

内容的提问来源于stack exchange,提问作者Leo Jiang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 00:52:41