这一篇想跟大家聊一个细节问题:为什么 build() 不在 StatefulWidget 外面而在 State 外面呢?

通常咱们写一个无状态组件 StatelessWidget 是这样的:

class Foo extends StatelessWidget {  @override  Widget build(BuildContext context) {    return Container();  }}

有状态组件 StatefulWidget 把可变的状态变量放到了 State 对象中,参照 StatelessWidget 的形式,把 build() 办法放到 StatefulWidget 中行不行?比方这样:

class Foo extends StatefulWidget {  @override  Widget build(BuildContext context, State state) {    return Container();  }}

看起来如同没啥问题,须要状态值就从 state 变量去取就好了,放在 StatefulWidget 中还合乎习惯跟 StatelessWidget 是相似的。Fultter 没有这样去做的起因次要是从代码的封装和灵活性来思考的。

咱们晓得 Flutter 中的组件 Widget 是能够继承的。一旦咱们把某一种通用状态逻辑的 StatefulWidget 子类化,就会发现如果把 build() 放在 StatefulWidget 中将是一个不合理的实现形式。

这里举一个例子,比方显式动画组件的抽象类 AnimatedWidget,它外部的 State 负责解决了动画的监听事件和主动调用 setState 来使组件重绘。开发者在应用时须要重写 build() 来展现本人的 UI,如果像下面代码示例里 build() 在 StatefulWidget 中,那 AnimatedWidget 就必须在 build() 办法中把抽象类的 state 对象传递给子类。然而你应该发现了这里 state 是 AnimatedWidget 父类外部应用和实现的,子类不应该理解细节。而将 build() 放在 State 中则不会呈现这样的问题,AnimatedWidget 申明一个 build() 让子类使用者去实现,而后在本人的 State 中去调用 widget.build(),代码的封装和灵活性都显著好多了。

这里再顺带一提官网文档里讲的那个闭包捕捉的问题解释,说实话我感觉有点牵强例子没举好。官网文档在这里:https://api.flutter.dev/flutt...

有点意思的是我找到了过后对于这个问题的探讨:https://github.com/flutter/fl...

有人提出了和我一样的疑难:当父更新时,子组件 Widget 会从新创立是个新实例,如果说有闭包也是新的闭包哪来旧闭包问题一说?如下:

提出这个闭包问题的作者回复说这取决于是怎么用这个旧闭包的,有可能这个旧闭包被另外一个对象持有了。也没举出理论的场景和例子,有点牵强。

综上所述,build() 在 State 中的确是正当的。Flutter 中有很多这种设计上的衡量思考,值得好好学习哇~