整个子树会在flutter中的setState上重建吗?

时间:2020-05-07 20:40:10

标签: flutter

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

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

当我们调用setState函数时,将在子树的build上调用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对它没有影响。 我想知道是否应该进行优化以避免在调用MyWidget1函数时无用的setState构建。由于MyWidget1下的树可能太大,因此也将再次对其进行重建。

我的问题:

  1. 独立小工具(此处为MyWidget1)是否可以在setState上再次构建?

  2. 是否有更好的方法来处理这种情况,以免重新生成。

注意:我已阅读此question

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

我的疑问是:

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

2 个答案:

答案 0 :(得分:3)

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

是的,是的。在每个setState之后,将重建整个子树。

没关系,不用担心。

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

您需要一次又一次地重新创建这棵树,只是一个外观。还有另外两个并行树,它们不是轻量级的,也不会重新创建。将您的窗口小部件树进行比较,以查找系统应如何修改实际ui元素。

为什么所有这些麻烦,您可能会问。因为创建树很容易,维护树很困难。这种反应式声明框架使我们仅创建树而不维护树就可以摆脱。

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

答案 1 :(得分:0)

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”关键字,则每次父项 小部件重新绘制。