React Turbo - 优化React性能的终极解决方案
我曾在Facebook担任前端工程师,并创建了~4000颗星react-native-webrtc
TL;DR
React Turbo在编译时自动优化React性能,所以开发者不需要手动进行优化。
React的痛苦
React开发起来很可爱。JSX比模板更好。钩子对于业务逻辑的隔离和组成很强大。
React几乎拥有最好的开发者体验(DX),除了一件事:性能优化。
变更检测/Reactivity
我们不得不承认,React从来不是反应性的。React的*变化检测(或Reactivity)*策略是基于diff(价值比较)的。相对而言,Vue、Angular和Svelte是基于价值观察/订阅的。
价值比较
价值比较意味着。
- 我们需要对数值进行记忆和稳定,以避免不相关的重新计算;道具避免不相关的重新渲染。
- 我们不能自动实现细粒度的反应性 ,因为React中最小级别的反应性是组件(不是值或元素)。
问题1.就是为什么我们需要useMemo、useCallback、React.memo甚至是不可变的数据。我们通过订阅容器(如react-hook-form的<Controller render={( => />)来解决问题2。
因此,当我们遇到上述两个性能问题时,我们必须手动添加useMemo、useCallback或用包装。
而这是很糟糕的。
React Turbo
React Turbo是一个babel插件,可以在编译时转换React组件的变化检测策略。 从价值比较到价值订阅在编译时的变化检测策略。所以它变成了细粒度的反应性,并缓存了所有的值,以避免不必要的重新计算和重新渲染。
安装React Turbo后,你不需要写任何useMemo、useCallback,甚至使用Redux的reselect。实际上,你不需要修改/写任何代码来优化性能。
安装
vs. React Forget
听起来像React Forget,是吧?
不同的是React Forget仍然是基于价值比较的。
React Turbo是Value Subscription,可以在值计算和元素渲染方面实现细粒度的反应性。
而React Forget仍然不能实现细粒度的反应性。它只是把任何东西备忘化。举个例子。
价值比较与价值订阅
假设当你在组件A中有一个值text,而你把text从A传到组件B,B传到C,C传到D,...,最后Y传到Z,那么,Z中的使用了text。
当文本改变时,即使有React Forget,组件A、B、C、...和Z都会重新渲染。
这意味着组件A到Z中的所有变量和React元素都被**重新初始化,并重新创建以进行比较,**尽管大部分的值都是一样的(因为只有文本发生变化)。
开销
当你有一个像Facebook Ads Manager网站那样的大型应用时,同值变量和React元素的重新创建和比较(例如Vdom diff、useMemo、React.memo或reselect的createSelector**)** 的开销会损害性能(是的,我曾在那个代码库工作过,这很痛苦,也很愉快😉)。
特别是当像文本这样的价值频繁变化时,如打字,每个事件100-200ms,甚至拖动滑块()和颜色选择器,每个事件33ms,用户可以感觉到滞后。
有了React Turbo即价值订阅,当文本发生变化时,只有Z中的会重新渲染(Z不会重新渲染),因为只有那个订阅了文本。
没有比较发生。
这就是我们所说的细粒度的反应性。
它是如何工作的
基本上,它将状态 *(来自useState的值)*从普通的JavaScript值转换为可观察/可订阅的信号/原子,如Recoil、zustand和effector。
然后自动收集Component中的变量声明的依赖关系,以生成计算原子(像useMemo,其中linters提示缺少依赖关系)。
它还将每个React.createElement与它的依赖关系的订阅容器包装在一起(以实现元素的细粒度反应性)。
所有这些都在编译时进行了转换。
vs. MobX
不同之处在于MobX的值是可变的,而订阅是在运行时发生并决定的。
React Turbo的值仍然是不可变的,它在并发模式下工作,值订阅是在编译时决定的。
未来
React Forget是一个在编译时优化性能的伟大举措,但Value Subscription绝对比Value Comparison的开销小,性能好。所以我希望React核心团队能够采用React Turbo的概念。
注意事项
- 由React Turbo编译的组件/钩子可以与未被React Turbo编译的组件/钩子一起工作。所以我们不需要编译任何第三方库就可以在React Turbo应用中工作。
- React Turbo应用程序的包的大小不会成倍增加。通常情况下,它只会增加10-20%,就像你通过添加useMemo、useCallback来手动优化。
- React Turbo中的可观察原子现在是基于效应器的。
- React Turbo可以轻松解决useEvent想要解决的性能问题。React Turbo的回调仍然会发生变化,导致订阅的组件重新渲染,但因为它是细粒度的,所以不会损害性能。
React Turbo--优化React性能的终极解决方案》最初发表于Dev Geniuson Medium,在那里人们通过强调和回应这个故事继续对话。