适用于审查 Flutter/Dart 应用程序的全面、与库无关的清单。无论使用哪种状态管理方案、路由库或依赖注入框架,这些原则都适用。
pubspec.yaml 是干净的 —— 没有未使用的依赖项,版本已适当固定analysis_options.yaml 包含严格的 lint 规则集,并启用了严格的分析器设置print() 语句 —— 使用 dart:developer log() 或日志包.g.dart, .freezed.dart, .gr.dart) 是最新的或在 .gitignore 中dynamic —— 启用 strict-casts, strict-inference, strict-raw-types
!(感叹号操作符)而不是适当的空检查或 Dart 3 模式匹配 (if (value case var v?))this.field
catch (e) 没有 on 子句;应始终指定异常类型Error:Error 子类型表示错误,不应被捕获async:标记为 async 但从未 await 的函数 —— 不必要的开销late 过度使用:在可使用可空类型或构造函数初始化更安全的地方使用了 late;将错误推迟到运行时StringBuffer 而不是 + 进行迭代式字符串构建const 上下文中的可变状态:const 构造器类中的字段不应是可变的Future 返回值:使用 await 或显式调用 unawaited() 来表明意图final 可用时使用 var:局部变量首选 final,编译时常量首选 const
package: 导入List/Map
if-case,而不是冗长的 is 检查和手动类型转换(String, int) 代替一次性 DTOprint():使用 dart:developer log() 或项目的日志包;print() 没有日志级别且无法过滤build() 方法超过约 80-100 行_build*() 辅助方法被提取到单独的部件类中(支持元素重用、常量传播和框架优化)const 构造器 —— 防止不必要的重建const 字面量 (const [], const {})const
ValueKey 以在重新排序时保持状态GlobalKey —— 仅在确实需要跨树访问状态时使用build() 中使用 UniqueKey —— 它会强制每帧都重建ObjectKey
Theme.of(context).colorScheme —— 没有硬编码的 Colors.red 或十六进制值Theme.of(context).textTheme —— 没有内联的 TextStyle 和原始字体大小build() 中没有网络调用、文件 I/O 或繁重计算build() 中没有 Future.then() 或 async 工作build() 中没有创建订阅 (.listen())setState() 局部化到尽可能小的子树这些原则适用于所有 Flutter 状态管理方案(BLoC、Riverpod、Provider、GetX、MobX、Signals、ValueNotifier 等)。
ref.watch 依赖其他提供者是预期的 —— 仅标记循环或过度复杂的链copyWith() 或构造函数创建新实例,绝不就地修改== 和 hashCode(比较中包含所有字段)Equatable、freezed、Dart 记录或其他方式List/Map 暴露@action,Signals 上的 .value,GetX 中的 .obs)—— 直接字段修改会绕过变更跟踪ReactionDisposer,Signals 中的 effect 清理)AsyncValue)—— 而不是布尔标志 (isLoading, isError, hasData)// BAD — boolean flag soup allows impossible states
class UserState {
bool isLoading = false;
bool hasError = false; // isLoading && hasError is representable!
User? user;
}
// GOOD (immutable approach) — sealed types make impossible states unrepresentable
sealed class UserState {}
class UserInitial extends UserState {}
class UserLoading extends UserState {}
class UserLoaded extends UserState {
final User user;
const UserLoaded(this.user);
}
class UserError extends UserState {
final String message;
const UserError(this.message);
}
// GOOD (reactive approach) — observable enum + data, mutations via reactivity API
// enum UserStatus { initial, loading, loaded, error }
// Use your solution's observable/signal to wrap status and data separately
const 部件来阻止重建在树中传播.listen()) 在 dispose() / close() 中被取消.listen())setState 之前检查 mounted
await 之后使用 BuildContext 而不检查 context.mounted(Flutter 3.7+)—— 过时的上下文会导致崩溃BuildContext 绝不存储在单例、状态管理器或静态字段中setState, ValueNotifier)setState() —— 将状态变化局部化const 部件来阻止重建传播RepaintBoundary
AnimatedBuilder 的 child 参数处理独立于动画的子树build() 中对大型集合进行排序、过滤或映射 —— 在状态管理层计算build() 中编译正则表达式MediaQuery.of(context) 的使用是具体的(例如,MediaQuery.sizeOf(context))cacheWidth/cacheHeight 的 Image.asset 以按显示尺寸解码ListView.builder / GridView.builder 代替 ListView(children: [...])(对于小型、静态列表,具体构造器是可以的)deferred as)Opacity 部件 —— 使用 AnimatedOpacity 或 FadeTransition
operator == —— 使用 const 构造器代替IntrinsicHeight, IntrinsicWidth) 谨慎使用(额外的布局传递)pumpWidget 和 pump 被正确用于异步操作find.byType、find.text、find.byKey 使用得当pumpAndSettle 或显式的 pump(Duration)
Semantics 小部件在自动标签不足时提供屏幕阅读器标签ExcludeSemantics 处理纯装饰性元素MergeSemantics 将相关小部件组合成单个可访问元素semanticLabel 属性onPressed 回调——每个按钮都有作用或处于禁用状态SafeArea 小部件处理状态栏和安全区域AndroidManifest.xml 和 Info.plist 中声明LayoutBuilder 或 MediaQuery 实现响应式布局Flexible、Expanded、FittedBox
--dart-define,.env 文件从 VCS 中排除,或使用编译时配置.gitignore
^1.2.3)——允许兼容性更新flutter pub outdated 以跟踪过时的依赖项pubspec.yaml 中没有依赖项覆盖——仅用于带有注释/问题链接的临时修复package:other/src/internal.dart(破坏 Dart 包封装)path: ../../ 相对字符串analysis_options.yaml
Navigator.push 和声明式路由器Map<String, dynamic> 或 Object? 转换FlutterError.onError 以捕获框架错误(构建、布局、绘制)PlatformDispatcher.instance.onError 处理 Flutter 未捕获的异步错误ErrorWidget.builder(用户友好而非红屏)runApp 周围使用全局错误捕获包装器(例如 runZonedGuarded,Sentry/Crashlytics 包装器)if 检查analysis_options.yaml 并启用了严格设置strict-casts: true、strict-inference: true、strict-raw-types: true
// ignore:)有注释说明原因flutter analyze 在 CI 中运行,失败会阻止合并prefer_const_constructors——小部件树中的性能avoid_print——使用适当的日志记录unawaited_futures——防止即发即弃的异步错误prefer_final_locals——变量级别的不可变性always_declare_return_types——明确的契约avoid_catches_without_on_clauses——具体的错误处理always_use_package_imports——一致的导入风格下表将通用原则映射到流行解决方案中的实现。使用此表将审查规则调整为项目使用的任何解决方案。
| 原则 | BLoC/Cubit | Riverpod | Provider | GetX | MobX | Signals | 内置 |
|---|---|---|---|---|---|---|---|
| 状态容器 | Bloc/Cubit |
Notifier/AsyncNotifier |
ChangeNotifier |
GetxController |
Store |
signal() |
StatefulWidget |
| UI 消费者 | BlocBuilder |
ConsumerWidget |
Consumer |
Obx/GetBuilder |
Observer |
Watch |
setState |
| 选择器 | BlocSelector/buildWhen |
ref.watch(p.select(...)) |
Selector |
N/A | computed | computed() |
N/A |
| 副作用 | BlocListener |
ref.listen |
Consumer 回调 |
ever()/once() |
reaction |
effect() |
回调 |
| 处置 | 通过 BlocProvider 自动 |
.autoDispose |
通过 Provider 自动 |
onClose() |
ReactionDisposer |
手动 | dispose() |
| 测试 | blocTest() |
ProviderContainer |
直接 ChangeNotifier |
在测试中 Get.put |
直接测试 store | 直接测试 signal | 小部件测试 |