当前位置: 首页 > Web前端 > HTML

Flutter:灵魂拷问——为什么build()是在State里,而不是StatefulWidget?

时间:2023-03-29 12:33:50 HTML

本文想和大家聊一个详细的问题:为什么build()不在StatefulWidget中,而是在State中?通常我们这样写一个无状态组件StatelessWidget:classFooextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnContainer();}}一个有状态组件StatefulWidget,将可变状态变量放在State对象中,参考在StatelessWidget方式中,把build()方法放在StatefulWidget中可以吗?例如:classFooextendsStatefulWidget{@overrideWidgetbuild(BuildContextcontext,Statestate){returnContainer();}}好像没什么问题,直接从state变量中获取state值,放到StatefulWidget中也符合习惯,和StatelessWidget类似。Fultter之所以没有这样做,主要是代码的封装性和灵活性。我们知道Flutter中的widget是可以继承的。一旦我们将一个带有通用状态逻辑的StatefulWidget子类化,我们会发现在StatefulWidget中实现build()是一种不合理的方式。这里举个例子,比如显式动画组件的抽象类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中有很多这样的设计权衡,值得学习~