现有React架构无法解决的问题

现有React架构无法解决的问题

大家好,我卡颂。

虽然主流前端框架都遵循:

  • 状态驱动视图
  • 单向数据流

理论上并不存在某一框架可以实现,其他框架无法实现的特性。

但是,确实存在某些框架(比如Vue、Qwik)可以,但React无法解决的问题。这就是「极致性能优化」问题。

本文来聊聊React性能优化无法解决的问题。

props下钻

前端框架普遍遵循「单向数据流」。既然是单向数据流,那就存在跨组件传递props的情况。

这种情况被称为「props下钻」(props drilling)。

比如,在下面的应用中:

  • <App/>组件定义状态number。
  • <AGrandChild/>组件消费number。
  • <BGrandChild/>组件包含改变number的方法setNumber。

这种将props(这里的number)层层向下传递(从<App/>到<AGrandChild/>)的情况,就是「props下钻」:

现有React架构无法解决的问题

「props下钻」是非常常见的场景。面对这种场景,React的性能怎么样呢?

props下钻的性能

思考一个问题:对于上面的例子,当调用<BGrandChild/>中的setNumber方法改变number后,哪些组件会重新render?

答案是:<App/>的所有子孙组件都会重新render。

这显然与我们的预期不符。

直觉上看,起码<B/>、<C/>及其子孙组件不应该render,毕竟他们都不依赖number。

为了达到这个目标,我们需要使用React.memo包裹<B/>、<C/>,这显然会带来额外的心智负担。

为了减少开发者的心智负担,在2021年的React Conf,黄玄带来了React Forget编译器,他能够为现有业务代码生成等效于useMemo、useCallback的代码。

也就是说,理想情况下,他能够代替开发者完成React项目的性能优化。

但是,回到我们的例子会发现 —— 即使做了性能优化,也无法达到最理想的状态。

整个应用中只有<AGrandChild/>消费了number,理想情况下,当number变化后,应该只有<AGrandChild/>需要render。

但在React中,即使性能优化后,<App/>与<AGrandChild/>沿途的组件也会render:

现有React架构无法解决的问题

而默认情况下(不优化性能),整个应用都会render:

现有React架构无法解决的问题

造成这一问题的原因在于 —— 对于任一状态,React不知道哪些组件依赖他。

在「props下钻」场景下,虽然<App/>与<AGrandChild/>沿途的组件仅仅是传递number(而不是依赖他),但React无从得知。

那如果明确的表示依赖关系,是不是能解决这个问题呢?

比如,我们不使用props,而是在<App/>定义context number,再在<AGrandChild/>中消费number:

现有React架构无法解决的问题

遗憾的是,在React中context的实现也是依赖组件树的遍历(可以理解为React内部实现的「props下钻」),所以并不能解决这个问题。

Signal

解决这个问题的关键在于 —— 明确状态与组件的依赖关系。

这种建立组件与状态之间依赖关系的技术叫「响应式更新」(熟悉Vue的同学应该不陌生),也有些框架称其为Signal。

应用这种技术的框架(比如Vue、Qwik),当状态变化,只有依赖该状态的组件会更新。

总结

正是由于React底层架构的原因,导致应用的性能优化无法达到最理想的状态。

这同时也是为什么React中有很多性能优化API(比如React.memo、useMemo、 useCallback…),而采用Signal技术的框架没有这些性能优化API的原因。

文章版权声明

 1 原创文章作者:7480,如若转载,请注明出处: https://www.52hwl.com/30354.html

 2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈

 3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)

 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023年7月14日 上午12:00
下一篇 2023年7月15日