ref.watchの動作
https://zenn.dev/mkikuchi/articles/cc87c84e1404c4 の記事でref.watchとrefreshListenableの組み合わせで、で想定していない動作になっていたので、HookConsumeWidgetでref.watchを使用した際に、どういう動作でそうなっているのかを理解したい。
ref.watch: プロバイダの値を取得した上で、その変化を監視する。値が変化すると、その値に依存するウィジェットやプロバイダの更新が行われる。
refはWidgetRefで、abstractクラス。
watchの他に、listenとread, refreshが定義されている。
HookConsumerWidgetは、COnsumerWIdgetを継承している。
ConsumerWidget内の、_ConsumerState内で、refのgetterを持っている。
WidgetRef get ref => context as WidgetRef;
watchの実装は、COnsumerStatefulElement内にある。
@override
Res watch<Res>(ProviderListenable<Res> target) {
return _dependencies.putIfAbsent(target, () {
final oldDependency = _oldDependencies?.remove(target);
if (oldDependency != null) {
return oldDependency;
}
return _container.listen<Res>(
target,
(_, __) => markNeedsBuild(),
);
}).read() as Res;
}
_dependenciesは、watchを呼んだProviderの値を管理している。
putIfAbsent
は、targetをKeyにするValueがあればそれを返して、なければtargetをKeyにするProviderSubscriptionの値を返す。
_oldDependenciesからtargetを削除して、値があれば削除したoldDependencyを返す。
それ以外の場合は、targetをlistenして、変更があればmarkNeedsBuild
を呼ぶ。
そして、取得したProviderのreadを呼んで値を返す。
つまり、ref.watch
を最初に呼んだときは、_dependencies
にProviderListenableな値をKeyとして、ProviderSubscriptionする値を追加する。
ProviderSubscriptionの値は、targetのProviderListenableをlistenして、変更があればmarkNeedsBuildでリビルドさせる。
そして、その値をread
で返している。
二回目以降を呼んだときは、_dependencies
にtargetのvalueがあるので、その値をreadで呼ぶだけ。