【问题标题】:DEBUG HELP: Flutter StatefulWidget doesn't maintain state(s) after scrolled out of view调试帮助:Flutter StatefulWidget 在滚动出视图后不保持状态
【发布时间】:2018-04-05 05:38:28
【问题描述】:

我正在玩一个简单的应用程序来学习 Flutter。这是 UI 的结构:

app -- MaterialApp -- HomeScreen (stateful) |- ListView -- PlaceWidget (stateful) |- ListTile

PlaceWidget 对象基本上构建并返回一个 ListTile;它唯一的额外职责是跟踪 favorited 状态并相应地构建 ListTile 的 UI。

源码为here,包括两个文件:

  • main.dart 用于整个应用,并且
  • places.dart 用于 http 请求

这是应用程序的行为方式:https://gfycat.com/FineBelovedLeafhopper


从表面上看,对象的状态似乎在滚动到视野之外时会丢失,但一些调试日志告诉我情况并非如此。

假设我最喜欢Oto Sushi,然后将其滚动到屏幕外,但保留指向状态对象的指针,该对象的favorited 状态仍将是true。然而,对象本身(属于_PlaceWidgetState 类)据报道为defunct, not mounted
我无法再与该对象交互。如果我再次点击 Oto Sushi,它将创建一个新的状态对象并将该对象的 favorited 状态设置为 true,就像以前一样。

只要我不将 Oto Sushi 滚动到屏幕外,我就可以取消收藏它并且一切正常。

我设法找到了TextInputFieldExpansionTile(例如this question)的类似问题,但我不知道如何将这些问题的解决方案转化为这个问题。

【问题讨论】:

  • 它不在视野范围内时不会渲染,因此不存在并且没有要维护的状态。你需要自己维护状态。
  • @GünterZöchbauer 您能否进一步说明我应该如何实现这一目标?当它滚动回视图时,它的build() 函数会再次被调用吗?我意识到我可以简单地将变量保持在更高范围内以跟踪状态,我只是想知道是否有“好的代码”标准解决方案。
  • 当然,build 将再次被调用。 build 通常也会在可见时被调用。我有一段时间没有对此进行调查,但如果它失去状态,initState 也应该在它变得可见时再次渲染时被调用。
  • 谢谢!我用MyApp 范围内的静态变量制作了一个肮脏的解决方案,以跟踪状态并检查build() 方法中的状态;它现在工作正常。如果您对如何干净利落地提出建议,我将不胜感激。
  • medium.com/@mehmetf_71205/inheriting-widgets-b7ac56dbbeb1 你可能会感兴趣。 Redux 也经常用于维护状态,通常与 InheritedWidget 一起使用。

标签: scroll persistence state flutter


【解决方案1】:

所以,抛开架构讨论不谈,问题的原因在于您如何构造 State 对象。通过将数据传递给构造函数,您可以确保每次重建小部件时,它们的状态都会重置。

 class PlaceWidget extends StatefulWidget {
  @override
  _PlaceWidgetState createState() {
    return new _PlaceWidgetState(place, false); // woops, always unchecked
  }

  final Place place;
  PlaceWidget(this.place, {Key key}) : super(key: key);
}

class _PlaceWidgetState extends State<PlaceWidget> { ... }

不要这样做,而是使用状态小部件内部的widget getter 来访问place 成员。还要确保您只在 State 小部件内初始化 checked 状态 - 或从此处的某个外部源获取它。

class _PlaceWidgetState extends State<PlaceWidget> {
  bool _isChecked = false; // only store state in State

  Widget build() {
   final Place place = widget.place;
   // build your stuff.
  }
}

现在您的小部件不断重建的原因是在ListView 中,屏幕外小部件可能会被破坏 - 它是为非常大的列表而设计的。为了防止这种情况,您还可以使用KeepAlive 小部件。

【讨论】:

  • 为了将来参考,如果像我这样愚蠢的人遇到这个问题,完整的解决方案包括: - 在 _PlaceWidgetState 中本地跟踪状态,并通过以下方式检索每个小部件的状态- 从InheritedWidget 中提取上下文。在 Jonah 的建议中,我们通过调用 inheritedWidget.of(context) 进一步更新 _isChecked,然后访问/更新 _isChecked 应该是的状态
猜你喜欢
  • 2022-01-19
  • 1970-01-01
  • 2021-11-15
  • 2011-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-07
相关资源
最近更新 更多