こちらは以下の続きになります。
背景
Riverpodを用いる際、stateの参照を行う場合にref.readやref.watchを用いることができますが、ref.readの場合思い通りにリビルドされなかったりとバグの要因にもなり得るためbuildメソッド内部ではref.watch
で統一したいところです。
そのため、ref.readで変数定義はしないような制約を設けました。
// This is the entrypoint of our custom linter
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';
/// メソッド呼び出し時にWidgetRefクラスのreadメソッドが呼ばれているかをチェックする
class NoRefReadVariableDeclarationInBuildMethod extends DartLintRule {
const NoRefReadVariableDeclarationInBuildMethod() : super(code: _code);
static const _code = LintCode(
name: 'no_ref_read_variable_declaration_in_build_method',
problemMessage: 'buildメソッド内部での変数定義時にref.readは使用しないでください',
errorSeverity: ErrorSeverity.ERROR,
);
@override
void run(
CustomLintResolver resolver,
ErrorReporter reporter,
CustomLintContext context,
) {
context.registry.addMethodInvocation((node) {
if (_isWidgetRefReadMethodInBuildMethod(node, resolver)) {
reporter.reportErrorForNode(_code, node);
}
});
}
bool _isWidgetRefReadMethodInBuildMethod(
AstNode node,
CustomLintResolver resolver,
) {
final buildMethod = node.thisOrAncestorOfType<MethodDeclaration>();
if (buildMethod == null || buildMethod.name.lexeme != 'build') {
return false;
}
if (node is MethodInvocation) {
final target = node.target;
final methodName = node.methodName.name;
if (target is SimpleIdentifier &&
target.name == 'ref' &&
methodName == 'read') {
final parent = node.parent;
if (parent is VariableDeclaration && parent.initializer == node) {
return true;
}
}
}
return false;
}
}
ただ力技が否めないのでもう少しいい方法があればコメントいただきたいです!
クラス定義をしたら、忘れず前回の記事にあるgetLintRules
にも追加しておきましょう。
PluginBase createPlugin() => _MyCustomLinter();
class _MyCustomLinter extends PluginBase {
@override
List<LintRule> getLintRules(CustomLintConfigs configs) => [
// 各lintルールを定義したクラスを配置していく
const NoRefReadVariableDeclarationInBuildMethod(),
];
}