使用 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 中包装了 Text
和 TextField
小部件,因此我们可以让 案例 1 解释 Text
小部件。
现在,转到TextField
小部件,将发生错误,因为TexField
小部件以任何方式不依赖于任何 obs 值(可观察值)。
需要注意的是,在提供给 textField 的 onChanged 回调中,controller
上调用的方法 updateString
对 TextField 的参数没有任何影响,因此这会导致 GetX 抛出错误,因为您正在尝试强制更新/重新构建一个不需要重新构建的小部件。
案例 3:当您将整列包裹在 Obx 中时(不会抛出错误,但不是最佳做法)。
在这种情况下,由于Text
小部件(位于列内)依赖于aString
的值,因此构建小部件时不会出现任何错误。那么,让我们看看当方法 updateString
被调用时会发生什么。
当 updateString
被调用时,整个 Column 被重新构建(连同 TextField
和 Text
小部件,此操作也将导致 Text
小部件中的值被更新。
现在,您可以看到为什么这第三种情况可能是有害的,如果您尝试将整个应用程序包装在 Obx 中,那么您的整个应用程序将不得不重新构建(这确实会对您的应用程序的性能产生负面影响。当然 GetX 有办法不允许这样做,因此当您尝试在 Obx 或 GetX 中包装 HeavyWidget 时会引发错误。
【讨论】:
所以我可以调用 GetxController 方法并从 Obx 外部更改字段。小部件被包裹在 Obx 中只是为了更新它们的值,对吧? 这听起来像是案例 3,虽然简单且方便,但与setState()
存在相同的缺点,其中整个小部件都在不断重建,比真正需要的要频繁。
是的,类似的。以上是关于使用 GetX 可观察对象时,哪些 UI 小部件需要包装在 Obx 中?的主要内容,如果未能解决你的问题,请参考以下文章
在底部表 GetX 库中调用 update() 时小部件不更新