【问题标题】:Is it ok to reuse widgets on subsequent build in Flutter?可以在 Flutter 的后续构建中重用小部件吗?
【发布时间】:2021-02-17 17:17:40
【问题描述】:

我一直在四处寻找,并没有找到一个合适的答案来回答这个问题:在后续的构建调用中重用小部件是否可以?我的意思是我创建了一个StatefulWidget,并在构建函数中保留了对返回的小部件的内部引用。在以后的构建中(如果我确定自上次构建以来没有任何变化),然后我返回最后一个小部件而不是构建一个新小部件。

我知道应该避免这种情况,创建简单的构建并优化失效过程,这样复杂的小部件就不会经常重建。但在某些情况下,我发现这可能是一个很好的解决方案。

特别是阅读this official doc page,它指出:

当重新遇到与前一帧相同的子小部件实例时,重建所有后代的遍历将停止。这种技术在框架内大量使用,用于优化不影响子子树的动画。请参阅 TransitionBuilder 模式和 SlideTransition 的源代码,它使用此原理来避免在制作动画时重建其后代。

所以这样做应该是可以接受的:

abstract class SmartState<T extends StatefulWidget> extends State<T> {
  Widget _lastBuild;
  T _previousWidget;

  bool shouldRebuild(T previousWidget);
  Widget doBuild(BuildContext context);

  @override
  @mustCallSuper
  Widget build(BuildContext context) {
    final T previousWidget = _previousWidget;
    _previousWidget = widget;

    if (previousWidget != null && _lastBuild != null && !shouldRebuild(previousWidget)) {
      return _lastBuild;
    }

    _lastBuild = doBuild(context);
    return _lastBuild;
  }
}

作为一点背景知识,我打算在一个列表项中扩展这个类。列表本身有时会更改并使用新项目重新构建,尽管大多数项目保持不变,我只是重新排列它们,删除或添加一些。另请注意,由于设计要求,我不得不将它们放在 Wrap 小部件中。

那么有没有人有任何反指示或比这更好的解决方案。最重要的是,我想知道进行这样的重用是否被认为是好的或好的做法。谢谢!

【问题讨论】:

    标签: performance flutter build statefulwidget


    【解决方案1】:

    你没有必要与框架争吵,flutter 内部通过使用 canUpdate() 方法等方法来处理重建。 https://api.flutter.dev/flutter/widgets/Widget/canUpdate.html.

    并为您的解决方案减少构建方法调用。您实际上使您的小部件实例化过于复杂。如果没有性能提升,我会说性能可能更差(请不要介意)。因为每当调用构建时,您总是向 SmartState 类抛出一个新对象,除非这些小部件具有 const 构造函数(这有助于运行时最终对象),或者您可以从上面的链接中看到小部件在两个基础键上进行比较和运行时类型,虽然我会说 constConstructor 会更好,但 dart 和其他语言对对象而不是 const 变量有更多的支持。大多数对象处理任务由 dart() 自己处理。

    所以要最终确定我的答案,您可以这样做,这可能会消除您的疑问。在任何有状态的小部件中执行此操作,您可能会找到答案

      void initState() { 
        super.initState();
      print( SizedBox() == SizedBox());  //OutPut: false 
      }
    

    一个快速的解决方案是创建一个这样的类。

    class WidgetConstant {
      static const SizedBox _sizedBox = SizedBox(
        height: 2,
      );
    
      WidgetConstant._();
      static Widget sizedBox() => _sizedBox;
    }
    

    现在使用下面的代码进行比较

    void initState() { 
        super.initState();
      print( WidgetConstant.sizedBox() == WidgetConstant.sizedBox(););  //OutPut: true 
    }
    

    结论:flutter 已经过优化,所以请享受使用这个高性能框架?。

    【讨论】:

    • 感谢您的详细回答。我明白你在说什么,但我可以说我真的看到了在这个用例中使用我的 SmartState 类有很大的改进。我知道比较 2 个新实例化的小部件不会相等。我认为您对 canUpdate 方法的作用有误。它比较 2 个给定的小部件,以查看框架是否可以将它们视为等效的,就好像新的小部件是旧小部件的替代品一样。
    • 另外,在我之前引用的文档中,它说“当再次遇到与前一帧相同的子小部件实例时”,这意味着它实际上是同一个实例,不是新创建的(widgetA == widgetB)。所以在我的理解中,返回之前构建的小部件应该可以(并且实际上可以)这个技巧。
    猜你喜欢
    • 2020-09-01
    • 2020-01-23
    • 2019-11-28
    • 2020-06-30
    • 2021-09-22
    • 1970-01-01
    • 2020-06-09
    • 2020-11-11
    • 2012-01-29
    相关资源
    最近更新 更多