正如Remi反复雄辩地指出的那样,并不是函数本身造成了问题,问题在于我们认为使用函数与使用新的小部件具有类似的好处。
不幸的是,这一建议正在演变成“仅仅使用一个函数的行为是低效的”,对其原因的猜测往往是错误的。
使用函数几乎等同于使用函数返回的内容来代替该函数。因此,如果您正在调用一个小部件构造函数并将其作为子部件赋予另一个小部件,那么将构造函数调用移到函数中并不会使代码效率降低。
//...
child: SomeWidget(),
//...
在效率方面是否明显优于
//...
child: buildSomeWidget();
//...
Widget buildSomeWidget() => SomeWidget();
关于第二个问题,可以提出以下论点:
它是丑陋的
这是不必要的
我不喜欢它
功能未出现在颤振检查器中
有两个函数可能无法与AnimatedSwitcher等一起工作。
它不会创建一个新的上下文,所以您不能通过上下文到达它上面的Scaffold
如果在其中使用ChangeNotifier,则其重建不会包含在函数中
但这样说是不对的:
就性能而言,使用函数是低效的
创建一个新的小部件可以带来以下性能优势:
其中的ChangeNotifier不会在更改时重新构建其父对象
兄弟小部件受到保护,不受彼此重建的影响
使用const创建它(如果可能的话)可以保护它不受父节点的重新构建
如果可以将不断变化的子部件隔离到其他小部件,则更有可能保留const构造函数
However, if you do not have any of these cases, and your build function is looking more and more like pyramid of doom, it is better to refactor a part of it to a function rather than keeping the pyramid. Especially if you are enforcing 80 character limit, you may find yourself writing code in about 20 character-wide space. I see a lot of newbies falling into this trap. The message to those newbies should be "You should really be creating new widgets here. But if you can't, at least create a function.", not "You have to create a widget or else!". Which is why I think we have to be more specific when we promote widgets over functions and avoid being factually incorrect about efficiency.
为方便起见,我重构了Remi的代码,以表明问题不只是使用函数,而是避免创建新的小部件。因此,如果您将在这些函数中创建小部件的代码放到调用函数的地方(refactor-inline),您将获得与使用函数完全相同的行为,但不使用函数!因此,问题不在于使用函数,而在于避免创建新的小部件类。
(记得关闭空安全,因为原始代码是2018年的)
这里有一些达特帕德的互动例子,你可以运行
让自己更好地理解问题:
https://dartpad.dev/1870e726d7e04699bc8f9d78ba71da35这个例子
展示了如何通过将你的应用程序分成功能,你可以
不小心弄坏像AnimatedSwitcher这样的东西
非功能版本:https://dartpad.dev/?id=ae5686f3f760e7a37b682039f546a784
https://dartpad.dev/a869b21a2ebd2466b876a5997c9cf3f1这个例子
展示了类如何允许更细粒度的小部件树重建,
改善性能
非功能版本:https://dartpad.dev/?id=795f286791110e3abc1900e4dcd9150b
https://dartpad.dev/06842ae9e4b82fad917acb88da108eee这个例子
展示了如何通过使用函数来暴露自己被滥用的风险
BuildContext和在使用InheritedWidgets(例如
主题或提供者)
非功能版本:https://dartpad.dev/?id=65f753b633f68503262d5adc22ea27c0
您会发现,在函数中不使用它们会产生完全相同的行为。所以添加小部件会让你获胜。并不是添加函数会产生问题。
所以建议应该是:
Avoid the pyramid of doom at any cost! You need horizontal space to code. Don't get stuck at the right margin.
Create functions if you need, but do not give parameters to them as it's impossible to find the line that calls the function through Flutter Inspector.
Consider creating new widget classes, it's the better way! Try Refactor->Extract Flutter Widget. You won't be able to if your code is too coupled with the current class. Next time you should plan better.
Try to comment out things that prevent you from extracting a new widget. Most likely they are function calls in the current class (setState, etc.). Extract your widget then, and find ways of adding that stuff in. Passing functions to the constructor may be ok (think onPressed). Using a state management system may be even better.
我希望这可以帮助提醒我们为什么更喜欢小部件而不是函数,并且简单地使用函数并不是一个大问题。
编辑:在整个讨论中有一点被忽略了:当你小部件化时,兄弟姐妹不再相互重建。这个达特帕德证明了这一点:https://dartpad.dartlang.org/?id=8d9b6d5bd53a23b441c117cd95524892