Flutter 又 7 个最佳实践

前言

构建更好、更廉价、更健壮的应用程序的最佳实践

Flutter 是 Google 开发的一个开源框架,它可能是当今最受欢迎的跨平台应用程序开发工具。它于 2017 年发布,从那时起,社区已经发展得如此之快,你可以通过谷歌找到足够的帮助。

自从我开始使用 Flutter 2.0 为 iOS 和 Android 开发应用程序以来,本文中的概念和技巧是我学到的一部分。然而,本文中的实践是为 Flutter 3 + 设计的(但它们也都适用于 Flutter 2 +)。

正文

1. 拆分业务

在 Flutter 中很容易混合关注点,因为逻辑层和表示层非常紧密,这使得代码更难长期维护,更容易出错,并且更容易重复自己。

然而,有多种技术可以用来分解关注点:

  • 创建用于管理条件句的函数,而不是直接在 Widget 中使用三元运算符
  • 将对 API 的调用移动到不同的文件夹/文件中,或者为它们创建一个 SDK 更好,这样您也可以在其他项目中重用该逻辑
  • 实现像 BloC、仓库或 MVVM 这样的体系结构模式; 只要有一些模式可以提供代码结构,选择哪种模式并不重要

例如,不像下面这样管理条件语句:

生成方法中的三元运算符示例

做以下事情:

构建方法外部的三元运算符示例

创建 widget 来重用代码

widget 是 Flutter 的家务,它们是一切,而且所有的东西都是作为一个 widget 在引擎盖下工作的。这可能就是为什么在 Flutter 中开发这么容易的原因。

创建可重用的 widget 有两种方法:

  • 使用返回 widget 的方法; 应该避免使用这种方法,因为它会在每次调用生成方法时重新生成返回的 widget
  • 创建一个 extension 自 StatelessWidget 或 StatuseWidget 的类; 两者都是首选的,因为 Flutter 尝试缓存它们的内容,但是,只有在需要更改状态时才应该使用有状态 widget

一般来说,使用助手函数或类可以避免重复使用,并使代码看起来更干净、更容易维护,但是总是更愿意使用类来获得更好的性能(和可测试性)。

避免做以下事情:

使用 helper 方法构建返回卡的 widget

改为:

使用类构建返回卡的 widget

3. 注意构建方法内部的逻辑

一个常见的好的和安全的假设是,在每一帧上,一个 Widget 都会调用 build 方法,这样 Flutter 就知道要渲染什么了。它通常不是那么关键(除非您的代码正在执行某些非常奇怪的操作) ,但是仍然经常调用构建方法,使得我们在方法中所做的任何事情都会被重新构建,除非被缓存。

大部分的 Widgets 已经被缓存了,但是业务逻辑、期货和繁重的任务将在 build 方法中再次执行,导致应用程序感到滞后和缓慢,因此损害了应用程序的用户体验。

解决这个问题的三个简单方法是:

  • 将业务逻辑移出构建方法(它再次分离关注点)
  • 只要有可能就使用 const,因为 widget 只会尝试有效地重新构建非常量内容,从而使重新构建更快,应用程序感觉更好,从而提高用户体验
  • 确保只触及构建方法之外的 API 端点; 我将在下一节中解释如何有效地使用 FutureBuilder

4. 不要在 FutureBuilder 中执行 future()

FutureBuilder 是一个令人惊异的 widget ,它通过根据具体情况呈现特定的 widget 来显示未来的不同状态,如等待、成功和错误响应。可以这样使用(避免) :

每次执行构建方法时,FutureBuilder 都会调用 future

问题是 FutureBuilder 是一个 widget ,因此存在于构建方法中,正如前面解释的那样,在屏幕生命周期中多次调用构建方法,使它每次都能回想起未来。如果它是您的 API,那么它可能会增加服务器成本,或者它甚至可能是与端点的每次命中相关的成本的第三方 API。此外,它会使你的应用程序感觉更慢,用户体验会受到打击。

尽管如此,解决方案很简单: 您只需要在构建方法之外调用 future,并且只使用 FutureBuilder 检索内容。它仍然会有不同的状态,但未来只能解决一次。下一张图片是基于前一段代码的正确实现的示例:

FutureBuilder 只调用将来的结果,而不调用自己

5. 在 setState() 中避免重逻辑

有状态 widget 有一个非常棒的方法来告诉 widget 代码中的某些内容已经发生了变化,需要重新构建自己; 这就是 setState() 方法。

如果你想修改一个变量并且让 UI 知道这个变化,你必须在 setState 内部进行,但是,因为它负责告诉 widget 重新构建自己,它应该只有所需的变化,否则 UI 会变得迟缓和缓慢(特别是因为 setState 是一个同步方法)。

这里的最佳实践是避免在对 setState() 的调用中使用繁重的逻辑,而是在外部进行繁重的提升,并且只指示通过 setState() 在 UI 中显示的确切更改。例如:

SetState 方法使用的不好和好的例子

6. 避免不必要的 container

来自 web 开发的开发人员倾向于在 Flutter 使用 container widget ,就像他们在 HTML 中使用 div 一样。我在这里告诉你: 停止这样做。 container 需要很多东西才能在引擎盖下工作,它们很重,如果你只是用它们来包装其他 widget ,它们很容易降低 FPS 并使应用程序滞后。不要误解我的意思,它们经常被需要,而且它们的存在是有原因的,但是,这里的想法是只在你真正需要它们的时候使用它们,因为在 container 中包装一个没有其他参数设置的 widget 没有任何效果,并且使代码变得不必要的复杂。

此外,当您认为需要一个 Container 时,首先查找 Widget Catalog,看看是否有另一个 Widget 已经满足您的需要。你可能会对 Flutter 已经建成的东西感到惊讶。

第一个示例,在不需要时使用 Container:

不需要 container 时使用 container

第二个例子,当有另一个 widget 效率更高时使用 Container:

当 SizedBox 更有效时使用 container

7. 始终使用数据类型

Dart 允许我们使用 var 声明动态数据类型,因为动态数据类型负责这些值; 当您不知道所拥有的变量的数据类型时(通常是从 API 获取数据时) ,这很有用。但是,动态数据类型可能成为一个健壮的噩梦,使您的代码更容易出现运行时错误,同时使用适当的数据类型,您可以从编译器获得帮助,可能还可以从 IDE 获得帮助。

我对此的一点建议是避免使用动态数据类型和 var 声明,强迫自己理解数据的含义,如果可以选择不放置类型,那么还是放置它。

对于最后一条建议,一个特别有用的例子是在使用 FutureBuilder 和 AsyncSnapshot 时不使用类型:

IDE 和编译器都不知道快照要检索什么数据,这是导致运行时错误的一个常见原因。但是,如果您添加数据类型,他们可以在编译时知道并通知您错误:

正如我们所看到的,快照所期望的数据类型是一个 String,它甚至抛出了一个错误,因为将来不会返回一个 String。这个简单的红色高光可能是长夜和短夜的区别。始终使用数据类型!

请继续关注更多这样的文章。如果你想让我写一些东西,特别是,让我知道在评论。

我是一个爱好学习的人,所以我很乐意阅读你们的意见和任何反馈,继续我的学习之路,请去留言!

感谢您阅读这篇文章,让我们一起创造一个更美好的世界吧! 弃

如果你喜欢的话,可以关注更多并分享它

结束语

如果本文对你有帮助,请转发让更多的朋友阅读。

也许这个操作只要你 3 秒钟,对我来说是一个激励,感谢。

祝你有一个美好的一天~

猫哥课程


© 猫哥

  • 微信 ducafecat

  • https://wiki.ducafecat.tech

  • https://ducafecat.com

Last Updated:
Contributors: ducafecat