深入理解 useTransition
useTransition 很难用
React 官方文档中关于 useTransition 的例子,我们首先点击 Post (slow)
按钮,马上再点击其他按钮,由于按钮点击响应事件使用了 startTransition
,从而不会因为 <PostsTab />
组件耗时而导致的冻结用户界面。
但是,我们注意到,例子中,将耗时组件 <PostsTab />
使用 memo
包起来了。如果我们删除 memo
,按照上述的操作首先点击 Post (slow)
按钮,等到 Posts 加载出来后,再点击其他按钮,明显页面卡顿了,仅仅是删除了 memo
,useTransition
就「失效」了 😭🤔️。
useTransition 会导致渲染两次
我们需要知道的是,调用 useTransition
时,会触发两次渲染,首先优先级高的任务会先渲染(例如点击按钮事件),然后才会进行 startTransition
回调中触发的优先级低的渲染。
在例子中,当我们在父组件 TabContainer
中,每次点击按钮时(即调用了 startTransition
),就会导致两次渲染。
所以,当我们处于 Post (slow)
按钮时,再点击其他按钮,导致 TabContainer
首先重新渲染,即会导致非常耗时的 <PostsTab />
组件重新渲染(这也就是 React 文档中,为什么需要使用 memo
而防止这个两次渲染导致的问题)。
我们在代码中加入 <Profiler />
,分别在按钮、下面内容和 App 本身渲染时打印日志,我们可以看到,当处于 Post (slow)
按钮时,再点击其他按钮,会导致渲染两次。
如何正确的使用 useTransition
-
按照 React 文档中例子,配合
memo
使用(虽然文档中并没有明说🤔️)。 -
将
useTransition
放到子组件中,这样由useTransition
而导致的二次渲染,就仅仅是渲染<TabButton />
这个轻量级组件两次。
当处于 Post (slow)
按钮时,再点击其他按钮,console 打印的渲染日志,可见只有 <TabButton />
渲染了两次:
- 只在耗时组件使用
useTransition
,即仅当点击Post (slow)
按钮时,这样再点击其他按钮就并不会因为useTransition
而导致的二次渲染。
当处于 Post (slow)
按钮时,再点击其他按钮,console 打印的渲染日志:
总结
useTransition
会导致组件二次渲染,所以使用时需要特别注意子组件二次渲染导致的卡顿。