使用 GetX 可观察对象时,哪些 UI 小部件需要包装在 Obx 中?

Posted

技术标签:

【中文标题】使用 GetX 可观察对象时,哪些 UI 小部件需要包装在 Obx 中?【英文标题】:When using GetX observables, which UI widgets need to be wrapped in Obx? 【发布时间】:2021-10-07 05:38:18 【问题描述】:

为了学习 GetX,我创建了一个简单的控制器类:

class MyDataController extends GetxController 
  RxString aString = ''.obs;

  void updateString(String s) 
    aString.value = s;
  

aString 的值显示在两个类中:AppBar(此处未讨论)和另一个同时设置和显示aString 的类:

class Level1 extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    final MyDataController controller = Get.find();
    final textController = TextEditingController();
    return Column(
      children: [
        TextField(
          controller: textController,
          onChanged: (_) 
            controller.updateString(textController.text);
          ,
        ),
        Text(controller.aString.value),
      ],
    );
  

我对哪些小部件需要包装在 Obx() 的实例中感到困惑。

如果我Text()(显示小部件)包装在Obx 实例中,它会在TextField()(输入小部件)更改时更新。如果我TextField() 小部件包装在Obx 实例中,我会收到一条错误消息:

在构建 Obx(has builder, dirty, 状态:_ObxState#019a0): [Get] 检测到 GetX 使用不当。 您应该只对将要更新的特定小部件使用 GetX 或 Obx。 如果您看到此错误,您可能没有在 GetX/Obx 中插入任何可观察变量 或将它们插入 GetX 认为适合更新的范围之外 (例如:GetX => HeavyWidget => variableObservable)。 如果您需要更新父窗口小部件和子窗口小部件,请将每个窗口小部件包装在 Obx/GetX 中。

一切似乎都很清楚:显示状态的小部件必须包装在 Obx() 实例中才能显示更新的变量。这很有意义。改变状态的小部件不需要包装在Obx() 实例中。

不过,我很困惑,因为如果我将 两个 小部件包装在单独的 Obx() 实例中,我会收到错误消息。但是,如果我将整个 Column() 包装在 Obx() 实例中,则当 TextField() 更改时,文本会正确更新。 ...我的理解中缺少什么?

【问题讨论】:

您能否具体说明您的问题,以便我尝试正确解释您想要什么? @AbdelrahmanM.Elmarakby 在使用 GetX 时,更改变量的状态,然后在值更改时自动更新 UI,哪些 UI 小部件应该(和不应该)由 Obx() 实例包装? 【参考方案1】:

当您将 Text 小部件包装在 Obx 中时,您就明白了。实际上,最好只在 Obx 中包装需要更新的最小小部件,在本例中为 Text 小部件。

让我解释一下你尝试测试它的情况发生了什么:

案例 1:当您仅将 Text 小部件包装在 Obx 中时(最好的做法)

这个案例恰好是最好的也是最受鼓励的方法。在这种情况下,当控制器 (MyDataController) 中的 aString 的值发生变化时,通知 Obx 从头开始​​重新构建受影响的Text 小部件,这是正是 GetX 的目标。

案例 2:当您将 Text && TextField 小部件都包装在 Obx 中时(这将引发错误)。

在这种情况下,您已经在 Obx 中包装了 TextTextField 小部件,因此我们可以让 案例 1 解释 Text 小部件。 现在,转到TextField 小部件,将发生错误,因为TexField 小部件以任何方式不依赖于任何 obs 值(可观察值)。 需要注意的是,在提供给 textField 的 onChanged 回调中,controller 上调用的方法 updateString 对 TextField 的参数没有任何影响,因此这会导致 GetX 抛出错误,因为您正在尝试强制更新/重新构建一个不需要重新构建的小部件。

案例 3:当您将整列包裹在 Obx 中时(不会抛出错误,但不是最佳做法)。

在这种情况下,由于Text 小部件(位于列内)依赖于aString 的值,因此构建小部件时不会出现任何错误。那么,让我们看看当方法 updateString 被调用时会发生什么。 当 updateString 被调用时,整个 Column 被重新构建(连同 TextFieldText 小部件,此操作也将导致 Text 小部件中的值被更新。 现在,您可以看到为什么这第三种情况可能是有害的,如果您尝试将整个应用程序包装在 Obx 中,那么您的整个应用程序将不得不重新构建(这确实会对您的应用程序的性能产生负面影响。当然 GetX 有办法不允许这样做,因此当您尝试在 Obx 或 GetX 中包装 HeavyWidget 时会引发错误。

【讨论】:

所以我可以调用 GetxController 方法并从 Obx 外部更改字段。小部件被包裹在 Obx 中只是为了更新它们的值,对吧? 这听起来像是案例 3,虽然简单且方便,但与 setState() 存在相同的缺点,其中整个小部件都在不断重建,比真正需要的要频繁。 是的,类似的。

以上是关于使用 GetX 可观察对象时,哪些 UI 小部件需要包装在 Obx 中?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Getx 小部件-Flutter 运行时显示错误

在底部表 GetX 库中调用 update() 时小部件不更新

Flutter GetX 状态管理不起作用

Kendo UI,使用 MVVM 时如何从 DOM 元素获取小部件对象?

Flutter GetX 状态管理按钮单击

如何编写可维护的 UI 屏幕?