【问题标题】:Does whole subtree rebuilds on setState in flutter整个子树是否在颤振中在 setState 上重建
【发布时间】:2020-08-23 07:31:02
【问题描述】:

我是 Flutter 的新手,我真的很想知道当我们调用 setState 时,是否所有小部件的子树都会重建。

这里的子树是指该小部件下面的所有小部件树(包括该小部件作为根节点)。

当我们调用setState 函数时,会在子树的root node 上调用build 方法,从而触发其子树的构建方法。假设子树(该小部件的子级)的分支(此处为 MyWidget1)独立于状态变量。我注意到即使是独立的分支也会在父节点中调用的setState 上重建。

class _MyAppState extends State<MyApp> {
  int count=0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(children: <Widget>[ MyWidget1(),MyWidget2(count),],),
      floatingActionButton: FloatingActionButton(onPressed: ()=>setState((){count++;}),), 
    );
  }
}

class MyWidget1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) { print("widget builds 1");
    return Container(height: 100, color: Colors.orange,);
  }
}
class MyWidget2 extends StatelessWidget {
  final int count;
  MyWidget2(this.count);
  @override
  Widget build(BuildContext context) { print("widget builds 2");
    return Text(count.toString());
  }
}

这里我们可以看到MyWidget1是独立于状态变量的(这里是count),所以一般情况下setState应该不会对其产生影响。 我想知道是否应该进行任何优化以避免在调用setState 函数时构建无用的MyWidget1。由于MyWidget1 下方的树可能太大,因此也将再次重建。

我的问题:

  1. 这个独立小部件(此处为MyWidget1)是否可以在setState 上再次构建?

  2. 有没有更好的方法来处理这种情况以避免重建。

注意:我已阅读此question

在这个问题中,有一种方法可以避免无用的构建,方法是在构建方法之外创建一个独立分支的实例,

我的疑问是:

这是处理这种情况的方法还是其他更好的方法,或者这种情况根本没有那么大,因为树在 O(n) 时间内构建(我认为这不应该是答案,因为构建树可能是 O(n) 操作,但它可能包括许多耗时的操作,这些操作可能对优化不友好,一次又一次地无用地调用。

【问题讨论】:

    标签: flutter


    【解决方案1】:

    是的,MyWidget1 是在 setState 的基础上重建的。只要相信代码。调用setState后,调用build,调用MyWidget1的构造函数。在每个setState 之后,都会重建整个子树。旧的小部件被丢弃。但是,国家并没有被抛弃。状态实例继续存在,它们不会重新创建(参见 didUpdateWidget)。

    所以,是的。在每个setState 之后,都会重建整个子树。

    没关系,别担心。

    这里的小部件类是非常轻量级的类。 Dart 的垃圾收集器经过优化,可以实例化许多此类对象并将它们一起丢弃。

    你可以一次又一次地重新创建的这棵树只是一个门面。还有另外两棵不是轻量级且未重新创建的并行树。您的小部件树被区分在一起,以找出系统应该如何修改实际的 ui 元素。

    您可能会问,为什么会有这么多麻烦。因为创建树很容易,维护它们很困难。这种反应式声明框架让我们摆脱了只创建树而不维护它的情况。

    有一些关于 Flutter 内部的资源,您可以阅读更多相关信息。一个这样的资源是这个视频:https://www.youtube.com/watch?v=996ZgFRENMs

    【讨论】:

      【解决方案2】:
      class _MyAppState extends State<MyApp> {
        int count=0;
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            body: Column(children: <Widget>[ const MyWidget1(),MyWidget2(count),],),
            floatingActionButton: FloatingActionButton(onPressed: ()=>setState((){count++;}),),
          );
        }
      }
      
      class MyWidget1 extends StatelessWidget {
        const MyWidget1();
        @override
        Widget build(BuildContext context) { print("widget builds 1");
        return Container(height: 100, color: Colors.orange,);
        }
      }
      class MyWidget2 extends StatelessWidget {
        final int count;
        MyWidget2(this.count);
        @override
        Widget build(BuildContext context) { print("widget builds 2");
        return Text(count.toString());
        }
      }
      

      当构造函数以“const”关键字开头时,它允许 您可以缓存和重用小部件。

      在调用构造函数来启动小部件时,使用“const”关键字。通过使用“const”关键字调用,当其他小部件更改时,小部件不会重建 他们在树中的状态。如果省略“const”关键字,则每次父级时都会调用小部件 小部件重绘。

      【讨论】:

        猜你喜欢
        • 2023-04-04
        • 2020-08-05
        • 1970-01-01
        • 2019-01-14
        • 2020-10-18
        • 2022-01-15
        • 2021-02-14
        • 1970-01-01
        • 2020-10-31
        相关资源
        最近更新 更多