likes
comments
collection
share

【Flutter】原生setState与GetX的刷新差异,三种刷新方式到底什么场景下怎么用?

作者站长头像
站长
· 阅读数 48

Flutter开发中不同的布局刷新方式探讨

前言

我们团队使用 Flutter 开发也快两个月了,这次的事情是这样子的,我们项目是基于 GetX 实现的,同事写的一个长表单页面发生了刷新的卡顿。

在一顿逻辑判断与操作之后调用 GetX 框架的 update 刷新整个页面,而整个页面就被 GetBuilder 包裹的,要知道这可是整个页面可是有足足三个屏幕高度的表单啊。

这...你不卡谁卡。啊?那这... 到底怎么回事呢?

其实这么用 GetBuilder 与原生的 SetState 就没有区别了,都是全部rebuild,别被重新build吓到了,重新build不代表会重新渲染,但是性能消耗肯定是有的。

最简单的解决方式是分区使用 GetBuilder 或者使用局部刷新 Obx 来解决。

他们都是 GetX 的状态管理工具与原生的 setState 状态刷新还有点不一样,一起来看看吧。

一、GetBuilder刷新方案

GetX 的刷新方案分为手动刷新与自动刷新,GetBuilder 与 Obx ,分别对应范围刷新与局部刷新,基本的使用我就不介绍了,网上一搜大把的是。

先说 GetBuilder 的方案,直接上代码:

【Flutter】原生setState与GetX的刷新差异,三种刷新方式到底什么场景下怎么用?

例如我们把一些布局封装到方法中,我们先加 8个 item 再说。

当然如果有条件最好是抽成类会更好,这里先偷懒...

【Flutter】原生setState与GetX的刷新差异,三种刷新方式到底什么场景下怎么用?

此时如果我们调用 controller 的 update 会怎么样?它会刷新!

【Flutter】原生setState与GetX的刷新差异,三种刷新方式到底什么场景下怎么用?

二、原生的刷新方案对比

我们改为原生刷新的方案:

【Flutter】原生setState与GetX的刷新差异,三种刷新方式到底什么场景下怎么用?

每次刷新

可以看到是和 GetBuilder 是一样的效果,但是 GetBuilder 的效果是可以自定义作用域,可以选择一个或多个 GetBuilder 包括一个布局或容器,而不像 SetState 一样刷新全所有的布局。

当我们在一个高节点调用setState()的时候会构建再次build所有的Widget,虽然不一定挂载到Element树中,但是平时我们使用的Widget中往往嵌套多个其他类型的Widget,每个build()方法走下来最终也会带来不小的开销,因此通过各种状态管理方案,Stream等方式,只做局部刷新,是我们日常开发中应该养成的良好习惯。

虽然setState的调用并没有像 Widget 层那样,在渲染控制层的 Element 那一层重新构建全部element。但是,这并不代表 setState 的使用没问题,首先,像之前篇章说的那样,它会重新构建整个 Widget 树,这会带来性能损耗;其次,由于整个 Widget 树改变了,意味着整棵树对应的渲染层Element对象都会执行 update方法,虽然不一定会重新渲染,但是这整棵树的遍历的性能开销也很高。因此,从性能上考虑,还是尽量不要使用 setState——除非,这个组件真的很简单,而且下级组件没有或者很少。

大家也可以看看这些文章如何追踪 setState 的源码实现。

三、Obx的局部刷新

其实网上也有很多局部刷新的方案,例如provider,StreamBuidler,ValueNotifier ,StatefulBuilder,Bedrock等等的框架或工具,我这里不做扩展了,只说一下 GetX 的响应式局部刷新。

RxString textContent = "刷新操作".obs;

我们把原本的数据改为Rx包装格式。

修改代码为Rx格式对象赋值:

【Flutter】原生setState与GetX的刷新差异,三种刷新方式到底什么场景下怎么用?

修改使用RX对象的地方使用 Obx 包裹:

【Flutter】原生setState与GetX的刷新差异,三种刷新方式到底什么场景下怎么用?

执行刷新我们可以看到,没有 rebuild 的 Log , 它已经刷新好了。

【Flutter】原生setState与GetX的刷新差异,三种刷新方式到底什么场景下怎么用?

总结

最终究其本质都是基于 StatefulWidget 的 setState 封装,不管是 GetBuilder 还是 Obx 都是原生的实现,并没有高深的魔法,为什么我们还是推荐使用 GetBuilder 和 Obx 呢?主要还是刷新范围的问题,如果你不喜欢使用框架,直接自定义 StatefulWidget 块其实也是能实现同样的效果的。

既然都有了干嘛不用是吧,下面再简单的回顾一波:

原生State状态管理

setState 原生方式可以自行控制刷新,缺点是容器内其他布局都被重构了,如果需要避免重构重绘可能需要一些自定义逻辑(例如Key)去判断 canUpdate 操作。一般人都不会这么麻烦写这些东西的话不如使用 Obx 响应式精准指定刷新方便。

Obx 响应式状态管理

Obx 可以配合响应式字段局部的精准刷新避免父容器无效重构,缺点是字段变为响应式的Rx包装类,布局也需要被Obx包裹了,破坏了原生代码观赏性。

GetBuilder 状态管理器

GetBuilder 就是指定区域范围手动去刷新的,可以分区设置多个刷新区域,可选择单个控件或容器,在一些特定场景下有奇效,但是如果不理解滥用一样会导致性能问题。

那么到底要不要用 GetX ?

伪命题,用不用都行,看团队,看项目综合考虑,不过毕竟它是底层架构而不是功能模块,不能像功能模块(权限,多媒体,路径管理等)封装成引擎类可以随时替换。一旦你使用了 GetX 大概率以后都是换不下来,如果强行要换底层框架代价极大。

说这些并不是为了贬低 GetX 也不是为了安利 GetX,不吹不黑如果你已经用了 GetX 不如躺下来好好享受,无需再纠结原生的刷新,破坏了变量属性、破坏了 Widget 结构之类的纠结了。

如果躺平接受了 GetX 的刷新方案,GetBuilder 与 Obx 两者结合,一个指定区域范围手动刷新,一个是局部控件点对点刷新,一个整体一个局部两者配合使用,基本上可以覆盖任何场景,并且相对性能也会比原生 setState 要好(理论上)。

那么本期内容就到这里,如讲的不到位或错漏的地方,希望同学们可以评论区指出。有更多更好的方案也欢迎大家评论区交流。

如果感觉本文对你有一点点点的启发,还望你能点赞支持一下,你的支持是我最大的动力啦。

Ok,这一期就此完结。

【Flutter】原生setState与GetX的刷新差异,三种刷新方式到底什么场景下怎么用?

转载自:https://juejin.cn/post/7298926584123605019
评论
请登录