【问题标题】:Immutable vs Observable collections in FlutterFlutter 中的不可变集合与可观察集合
【发布时间】:2019-06-01 10:29:31
【问题描述】:

将 Flutter 与实时数据库(例如 Firebase 数据库)一起使用时,不仅要知道集合已更新,还要知道确切的更新位置。比如显示一个漂亮的list animation,或者根据哪个项目更新触发一些额外的事件。 Dart 已经有一个 amazing infrastructure 用于传递事件。

一个典型的例子是使用FirebaseAnimatedList,但它与Firebase 绑定,不支持过滤和排序(除了非常基本的Firebase model)。我正在寻找一个更通用的解决方案,它允许在数据库(通知项目更改/插入/删除)和前面提到的 AnimatedList 之间注入一些逻辑,它期望相同的事件。

最近的趋势似乎支持不可变集合,例如 built_value,这在 Dart 中很有意义,因为对象创建是 very cheap。但是,不可变集合无法判断哪个项目已更改,它们只是提供一个新集合。这种方法还使得难以将一些本地信息附加到项目,例如当用户多选项目或自定义排序时的“选择”位。因为,嗯,项目是不可变的,它们的引用(又名指针,又名对象 ID)不断变化。

另一种解决方案是实现一种可观察列表,例如package:observable 提供的列表,但似乎它的作者不再相信它的受欢迎程度。那么,在 Flutter 中创建动画、过滤、排序、选择支持列表并由实时数据库支持的方法是什么?

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    但是,不可变集合无法判断哪个项目已更改,它们只是提供一个新集合。

    一些伪代码:(old collection) - (new collection) = (what changed) - 反之亦然。

    这种方法也很难将一些本地信息附加到一个项目,例如当用户多选项目或自定义排序时的“选择”位。

    扩展所说的“项目”并添加属性selected(或order,或您想要的任何其他信息),然后只需正确设置这些属性即可构建新列表。

    这几天有很多与状态管理相关的问题,所以为了避免重复自己,我宁愿链接你到an answer of mine from earlier today.

    编辑:

    我只想插入一个关于(old collection) - (new collection) = (what changed)的实际示例:

    基本上,这是在比较两个包含密切相关元素的列表时如何查看发生了什么变化。

    List currentState = [...];
    List nextState = [...];
    
    List addedItems = nextState.where((e) => !currentState.contains(e)).toList(),
    List removedItems = currentState.where((e) => !nextState.contains(e)).toList();
    
    
    doSomethingWith(addedItems);
    doSomethingElseWith(removedItems);
    

    当然,您应该记住,列表应该具有高度可比性,即对于 Dart 的特定情况,您可以使用 built_valueequatable 包。

    我还上传了repository,带有纯 Dart 项目示例。非常欢迎你对代码做任何你想做的事情。

    【讨论】:

    • 那个伪代码效率很低,因为“改变了什么”是数据库首先给出的。并且找到以前的项目位置以正确地为其设置动画更加困难。出于同样的原因,扩展项目不是一个选项:一旦新数据到达,任何额外的状态都将被覆盖。
    • 我已经阅读了有关状态管理的答案,这很好,但没有告诉任何新内容。不幸的是,它根本无法回答我的问题。
    • 您不能保留对旧状态的引用,当您从数据库接收数据(新状态)时,只需将其与该引用进行比较。然后销毁对旧数据的引用(如果它是某种可听的),或者让 GC 完成它的工作。我还建议使用pub.dev/packages/equatable 而不是built_value(尽管它们的内置序列化非常好)来比较同一类的实例。
    • @J.Williams 我用一些更实用的代码更新了我的答案。我还查看了 AnimatedList 并且可以确认它有点混乱。它将声明性与命令式逻辑(即 AnimatedListState 的 removeItem() 和 insertItem())混合在一起......但最后,我评论中的相同逻辑应该适用于您的用例。
    • 谢谢,这是解决此问题的可行方法,但很难掌握。它有很多缺点:任何字段更改都会丢失项目的整个状态,因为它被“移除”了;我们丢弃了方便高效的数据库添加/删除/更改事件;分页效率低下,因为整个列表都被重新计算(O(n^2) 完全比较); AnimatedList 操作索引,所以它会更加复杂。我正在寻找可重用的东西,我不必在其中构建大量样板。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 1970-01-01
    • 1970-01-01
    • 2013-05-21
    相关资源
    最近更新 更多