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

When using GetX observables, which UI widgets need to be wrapped in Obx?

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

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

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

aString 的值显示在两个 class 中:AppBar(此处未讨论)和另一个 class,其中 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() 的实例中感到困惑。

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

The following message was thrown building Obx(has builder, dirty, state: _ObxState#019a0): [Get] the improper use of a GetX has been detected. You should only use GetX or Obx for the specific widget that will be updated. If you are seeing this error, you probably did not insert any observable variables into GetX/Obx or insert them outside the scope that GetX considers suitable for an update (example: GetX => HeavyWidget => variableObservable). If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.

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

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

当您将文本小部件包装在 Obx 中时,您已经掌握了所有内容。事实上,最好只包装需要在 Obx 中更新的最小小部件,在本例中为 Text 小部件。

让我解释一下您尝试测试它的情况:

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

这种情况恰好是最好和最受鼓励的方法。在这种情况下,当控制器 (MyDataController) 中 aString 的值发生变化时,Obx 会被通知重新构建 only 受影响的 Text widget,这正是GetX的目标。

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

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

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

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