Flutter代码质量检查插件grab_lints的使用
Flutter代码质量检查插件grab_lints的使用
简介
grab_lints
是一个用于 Flutter 的代码质量检查插件,可以帮助开发者发现并修正对 grab
库的常见误用。此插件依赖于 custom_lint
。
兼容性说明
请注意,此插件不兼容 grab
1.0.0-dev.1 及以上版本。由于 grab
较新版本的改进,不再需要 grab_lints
来避免旧版本中存在的误用问题。
安装与配置
pubspec.yaml
在项目的 pubspec.yaml
文件中添加以下依赖项:
dev_dependencies:
custom_lint:
grab_lints: x.x.x
analysis_options.yaml
在项目的 analysis_options.yaml
文件中启用 custom_lint
插件:
analyzer:
plugins:
- custom_lint
可用的检查规则
错误(Errors)
规则名称 | 是否可自动修复 | 详情 |
---|---|---|
missing_grab_mixin | ✅ | 在 with 子句中缺少必要的 Grab 混入类。 |
wrong_grab_mixin | ✅ | 小部件类中的 Grab 混入类不匹配。 |
警告(Warnings)
规则名称 | 是否可自动修复 | 详情 |
---|---|---|
unnecessary_grab_mixin | ✅ | 在 with 子句中存在不必要的 Grab 混入类。 |
maybe_wrong_build_context_for_grab | ✅ | 传递给 grab 方法的 BuildContext 存在问题,如不是来自 build 方法或通过变量传递。建议直接使用 build 方法的参数。 |
avoid_grab_outside_build | ❌ | grab 方法在小部件的 build 方法外被使用。虽然可能,但容易导致误用或混淆。 |
示例代码
以下是 grab_lints
的使用示例代码:
// ignore_for_file: avoid_single_cascade_in_expression_statements, invalid_override, mixin_application_not_implemented_interface, non_abstract_class_inherits_abstract_member, unused_element
//=========================================================
// 此文件既作为演示也作为测试。
// 如果 lint 警告成功被 `expect_lint` 注释抑制,则您的编辑器将不会显示错误。
//=========================================================
import 'package:flutter/material.dart';
import 'package:grab/grab.dart';
final valueNotifier = ValueNotifier(0);
final changeNotifier1 = MyChangeNotifier1(0);
final changeNotifier2 = MyChangeNotifier2(0);
final changeNotifier3 = MyChangeNotifier3(0);
final textController = TextEditingController();
class MyChangeNotifier1 extends ChangeNotifier {
MyChangeNotifier1(this.value);
final int value;
}
class MyChangeNotifier2 extends MyChangeNotifier1 {
MyChangeNotifier2(super.value);
}
class MyChangeNotifier3 with ChangeNotifier {
MyChangeNotifier3(this.value);
final int value;
}
void main() => runApp(const App());
class App extends StatelessWidget {
const App({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: const Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_StatelessWidget1(),
_StatelessWidget2(),
_StatelessWidget3(),
_StatelessWidget4(),
_StatefulWidget1(),
_StatefulWidget2(),
_StatefulWidget3(),
_StatefulWidget4(),
],
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () => valueNotifier.value++,
),
),
);
}
}
// expect_lint: unnecessary_grab_mixin
class _StatelessWidget1 extends StatelessWidget with Grab {
const _StatelessWidget1();
[@override](/user/override)
Widget build(BuildContext context) {
return const SizedBox.shrink();
}
}
class _StatelessWidget2 extends StatelessWidget with Grab {
const _StatelessWidget2();
[@override](/user/override)
Widget build(BuildContext context) {
// 使用 grab 在 if 条件或块中是允许的。
if (valueNotifier.grab(context).isEven) {
valueNotifier.grab(context);
}
int localFunc1() {
// 在局部函数中使用 BuildContext 参数是可以接受的。
return valueNotifier.grab(context);
}
int localFunc2(BuildContext context) {
// 如果 BuildContext 参数未直接使用,则会发出警告。
// expect_lint: maybe_wrong_build_context_for_grab
return valueNotifier.grab(context);
}
final ctx = context;
// build 方法的 BuildContext 参数应直接使用。
// expect_lint: maybe_wrong_build_context_for_grab
valueNotifier.grab(ctx);
return Center(
child: SizedBox.square(
dimension: 500.0,
child: Column(
children: [
Padding(
// 在深层嵌套位置使用 grab 是允许的。
padding: EdgeInsets.all(valueNotifier.grab(context).toDouble()),
child: Text('${valueNotifier.grab(context)}'),
),
...[
Text('${valueNotifier.grab(context)}'),
],
Builder(
builder: (_) {
// 在回调函数中使用 BuildContext 参数是可以接受的。
// 但是请注意,这会导致父级小部件和当前 Builder 重新构建。
return Text('${valueNotifier.grab(context)}');
},
),
Builder(
builder: (context) {
// expect_lint: maybe_wrong_build_context_for_grab
return Text('${valueNotifier.grab(context)}');
},
),
Builder(
builder: (context2) {
final context = context2;
// expect_lint: maybe_wrong_build_context_for_grab
return Text('${valueNotifier.grab(context)}');
},
),
],
),
),
);
}
}
// expect_lint: wrong_grab_mixin
class _StatelessWidget3 extends StatelessWidget with Grabful {
const _StatelessWidget3();
[@override](/user/override)
Widget build(BuildContext context) {
_func(context);
// expect_lint: missing_grab_mixin
return Text('${valueNotifier.grab(context)}');
}
void _func(BuildContext context) {
// expect_lint: avoid_grab_outside_build
valueNotifier.grab(context);
}
}
class _StatelessWidget4 extends StatelessWidget {
const _StatelessWidget4();
[@override](/user/override)
Widget build(BuildContext context) {
// 需要 Grab 或 StatelessGrabMixin。
// expect_lint: missing_grab_mixin
final count = valueNotifier.grab(context);
// expect_lint: missing_grab_mixin
changeNotifier1.grab(context);
// expect_lint: missing_grab_mixin
changeNotifier2.grab(context);
// expect_lint: missing_grab_mixin
changeNotifier3.grab(context);
// expect_lint: missing_grab_mixin
textController.grab(context);
// expect_lint: missing_grab_mixin
valueNotifier.grabAt(context, (v) => v);
// expect_lint: missing_grab_mixin
changeNotifier1.grabAt(context, (MyChangeNotifier1 n) => n.value);
// expect_lint: missing_grab_mixin
changeNotifier2.grabAt(context, (MyChangeNotifier2 n) => n.value);
// expect_lint: missing_grab_mixin
changeNotifier3.grabAt(context, (MyChangeNotifier3 n) => n.value);
// expect_lint: missing_grab_mixin
valueNotifier..grab(context);
return Center(
child: Text('$count'),
);
}
}
// expect_lint: unnecessary_grab_mixin
class _StatefulWidget1 extends StatefulWidget with Grabful {
const _StatefulWidget1();
[@override](/user/override)
State<_StatefulWidget1> createState() => _StatefulWidget1State();
}
class _StatefulWidget1State extends State<_StatefulWidget1> {
[@override](/user/override)
Widget build(BuildContext context) {
return const SizedBox.shrink();
}
}
class _StatefulWidget2 extends StatefulWidget with Grabful {
const _StatefulWidget2();
[@override](/user/override)
State<_StatefulWidget2> createState() => _StatefulWidget2State();
}
class _StatefulWidget2State extends State<_StatefulWidget2> {
[@override](/user/override)
Widget build(BuildContext context) {
// 使用 grab 在 if 条件或块中是允许的。
if (valueNotifier.grab(context).isEven) {
valueNotifier.grab(context);
}
int localFunc1() {
// 在局部函数中使用 BuildContext 参数是可以接受的。
return valueNotifier.grab(context);
}
int localFunc2(BuildContext context) {
// 如果 BuildContext 参数未直接使用,则会发出警告。
// expect_lint: maybe_wrong_build_context_for_grab
return valueNotifier.grab(context);
}
final ctx = context;
// build 方法的 BuildContext 参数应直接使用。
// expect_lint: maybe_wrong_build_context_for_grab
valueNotifier.grab(ctx);
return Center(
child: SizedBox.square(
dimension: 500.0,
child: Column(
children: [
Padding(
// 在深层嵌套位置使用 grab 是允许的。
padding: EdgeInsets.all(
valueNotifier.grab(context).toDouble(),
),
child: Text('${valueNotifier.grab(context)}'),
),
...[
Text('${valueNotifier.grab(context)}'),
],
Builder(
builder: (_) {
// 在回调函数中使用 BuildContext 参数是可以接受的。
// 但是请注意,这会导致父级小部件和当前 Builder 重新构建。
return Text('${valueNotifier.grab(context)}');
},
),
Builder(
builder: (context) {
// expect_lint: maybe_wrong_build_context_for_grab
return Text('${valueNotifier.grab(context)}');
},
),
Builder(
builder: (context2) {
final context = context2;
// expect_lint: maybe_wrong_build_context_for_grab
return Text('${valueNotifier.grab(context)}');
},
),
],
),
),
);
}
}
// expect_lint: wrong_grab_mixin
class _StatefulWidget3 extends StatefulWidget with Grab {
const _StatefulWidget3();
[@override](/user/override)
State<_StatefulWidget3> createState() => _StatefulWidget3State();
}
class _StatefulWidget3State extends State<_StatefulWidget3> {
[@override](/user/override)
Widget build(BuildContext context) {
_func(context);
// expect_lint: missing_grab_mixin
return Text('${valueNotifier.grab(context)}');
}
void _func(BuildContext context) {
// expect_lint: avoid_grab_outside_build
valueNotifier.grab(context);
}
}
class _StatefulWidget4 extends StatefulWidget {
const _StatefulWidget4();
[@override](/user/override)
State<_StatefulWidget4> createState() => _StatefulWidget4State();
}
class _StatefulWidget4State extends State<_StatefulWidget4> {
[@override](/user/override)
Widget build(BuildContext context) {
// 需要 Grabful 或 StatefulGrabMixin。
// expect_lint: missing_grab_mixin
final count = valueNotifier.grab(context);
// expect_lint: missing_grab_mixin
changeNotifier1.grab(context);
// expect_lint: missing_grab_mixin
changeNotifier2.grab(context);
// expect_lint: missing_grab_mixin
changeNotifier3.grab(context);
// expect_lint: missing_grab_mixin
textController.grab(context);
// expect_lint: missing_grab_mixin
valueNotifier.grabAt(context, (v) => v);
// expect_lint: missing_grab_mixin
changeNotifier1.grabAt(context, (MyChangeNotifier1 n) => n.value);
// expect_lint: missing_grab_mixin
changeNotifier2.grabAt(context, (MyChangeNotifier2 n) => n.value);
// expect_lint: missing_grab_mixin
changeNotifier3.grabAt(context, (MyChangeNotifier3 n) => n.value);
// expect_lint: missing_grab_mixin
valueNotifier..grab(context);
return Center(
child: Text('$count'),
);
}
}
更多关于Flutter代码质量检查插件grab_lints的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter代码质量检查插件grab_lints的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
grab_lints
是一个用于 Flutter 项目的代码质量检查插件,它基于 lints
包,提供了一组推荐的 lint 规则,帮助开发者遵循 Dart 和 Flutter 的最佳实践。使用 grab_lints
可以简化 lint 规则的配置,并确保项目代码风格一致。
安装 grab_lints
-
添加到
pubspec.yaml
文件在你的 Flutter 项目的
pubspec.yaml
文件中,添加grab_lints
作为开发依赖项:dev_dependencies: grab_lints: ^1.0.0
然后运行
flutter pub get
来安装依赖。 -
配置
analysis_options.yaml
文件在项目的根目录下创建或编辑
analysis_options.yaml
文件,并引入grab_lints
的规则:include: package:grab_lints/analysis_options.yaml
这个配置会将
grab_lints
提供的 lint 规则应用到你的项目中。
使用 grab_lints
-
运行代码分析
在终端中运行以下命令来执行代码分析:
flutter analyze
这将根据
grab_lints
提供的规则检查你的代码,并输出任何违反规则的地方。 -
自定义 lint 规则
如果你想在
grab_lints
的基础上添加或修改 lint 规则,可以在analysis_options.yaml
文件中进行自定义。例如:include: package:grab_lints/analysis_options.yaml analyzer: strong-mode: implicit-casts: false implicit-dynamic: false linter: rules: - avoid_print - prefer_const_constructors
在这个例子中,我们禁用了隐式类型转换和动态类型,并添加了
avoid_print
和prefer_const_constructors
两条规则。 -
集成到 CI/CD
你可以将
flutter analyze
集成到你的 CI/CD 流程中,以确保每次提交或构建时都进行代码质量检查。例如,在 GitHub Actions 中,可以添加如下步骤:- name: Analyze code run: flutter analyze