Flutterアプリを作っていると、以下のようなコードをよく書くと思います。
class SampleWidgetSate extends State<SampleWidget> {
AnimationController controller;
...
@override
void initState() {
super.initState();
controller = AnimationController(...);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
AnimationController、ScrollController、InputControllerなどはChangeNotifier
を継承しているので、Widgetのdisposeのタイミングでdiposeを呼ぶ必要があります。
ただ、管理すべき~Controllerの数が増えると、
これらを複数行うのは面倒だしボイラープレートの冗長なコードが増えてしまいます。
そこで、MixinとDart2.7で追加されたStatic Extension Functionでこれを簡単に書けるようにしました。
以下のようなMixInとExtensionを書きます。
import 'package:flutter/widgets.dart';
mixin AutoDisposeStateMixin<T extends StatefulWidget> on State<T> {
final _changeNotifiers = <ChangeNotifier>[];
void addDisposer(ReactionDisposer dispose) {
_disposers.add(dispose);
}
@override
void dispose() {
super.dispose();
for (final notifier in _changeNotifiers) {
notifier?.dispose();
}
}
}
extension AutoDisposeChangeNotifier on ChangeNotifier {
void disposedBy(AutoDisposeStateMixin state) {
state.addChangeNotifiers(this);
}
}
これをインポートすると、以下のように書くことができるようになります。
class SampleWidgetSate extends State<SampleWidget> with AutoDisposeStateMixin {
AnimationController controller;
...
@override
void initState() {
super.initState();
controller = AnimationController(...).disposedBy(this);
}
}
結構短く書けるようになりました。Controllerが複数あるとさらに差がわかりやすいと思います。
ExtensionはDart2.7以降の機能なので、まだどのプロジェクトでも使えるわけではないですが、 Dartの可能性を大きく広げる機能だと思います。
ちなみに、今回のAutoDisposeはRxSwiftのAPIに似せて作りました。
すでに拡張関数の利用例が豊富なKotlinやSwiftなどの先輩言語から 拡張関数の利用ケースを輸入するだけでも、コードをよりシンプルにできると思います。