##追記
riverpod v0.14からStateNotifierProviderの文法が変わりました。(参考: https://riverpod.dev/docs/migration/0.13.0_to_0.14.0/)
##対象者
本記事は、flutterとproviderを経験した人がriverpodに移行する際の手助けを目的としています。
##手短に
riverpodとは? => providerを改良した状態管理ライブラリです。
providerは無くなる? => 無くならないと思われます。
今すぐ乗り換えるべき? => 新規なら使っても良いと思います。providerで出来上がっているなら検討。
##何が変わるのか
ProviderがウィジェットからDartのオブジェクトに。
これがでかい。
その他の変更点は、その副作用と言っても良い。(と思っている)
//Provider
Provider<Hoge>(
create: (context) => Hoge(context),
child: Child(),
);
//riverpod
final hogeProvider = Provider<Hoge>(
(ref) => Hoge(ref),
)
StateNotifierProviderのStateのジェネリクスが不要になった。
追記
riverpod v0.14からStateNotifierProviderにStateのジェネリクスが必要になりました
//Provider
StateNotifierProvider<HogeController, HogeState>(
create: (context) => HogeController(context),
child: Child(),
);
//riverpod < 0.14
final hogeStateControllerProvider = StateNotifierProvider<HogeController>(
(ref) => HogeController(),
)
//riverpod >= 0.14
final hogeStateControllerProvider = StateNotifierProvider<HogeController, HogeState>(
(ref) => HogeController(),
)
refについては後述。
StateNotifierProviderのLocatorMixinは使えない。
残念。
ref
ウィジェット外からプロバイダーを参照する時に使います。read/watchが出来ます。
例えば
final hogeStateControllerProvider = StateNotifierProvider<HogeController>(
(ref) => HogeController(),
)
final anotherStateControllerProvider = StateNotifierProvider<AnotherController>(
(ref) => AnotherController(ref),
)
class AnontherController extends StateNotifier<AnotherState>{
AnontherController (ProviderReference ref){
//riverpod < 0.14
final hogeController = ref.read(hogeStateControllerProvider);
final hogeState = ref.read(hogeStateControllerProvider.state);
final hogeState = ref.watch(hogeStateControllerProvider.state);
//riverpod >= 0.14
final hogeController = ref.read(hogeStateControllerProvider.notifier);
final hogeState = ref.read(hogeStateControllerProvider);
final hogeState = ref.watch(hogeStateControllerProvider);
}
}
こんな風に。
watchすると、stateに変更があった場合にProviderのcreateがもう一度走り、Controllerが作り直されます。
ref或いはref.read/ref.watchをコントローラーの引数として渡すことがよくあります。
Consumerのwatch
context.watchが廃止され、代わりにConsumerというWidgetを使うようになります。
watch関数の引数にプロバイダーを入れて使います。
final hogeProvider = Provider<Hoge>(
(ref) => Hoge(ref),
)
@override
Widget build(BuildContext context) {
//廃止:context.watch<Hoge>();
return Consumer(
builder: (BuildContext context, T Function<T>(ProviderBase<Object, T>) watch, Widget child) {
//ここでwatchを使う
watch<Hoge>(hogeProvider);
//ジェネリクスは省略可(全てのread/watchで省略可)
watch(hogeProvider);
},
);
}
context.readは引き続きビルド時以外に使えます。
##要するに
Provider | riverpod |
---|---|
context.watch<Provider> | Consumerのwatch(provider) |
context.watch<State> | Consumerのwatch(provider.state) |
context.read<Provider> | context.read(provider) |
context.read<State> | context.read(provider.state) |
LocatorMixinのinitState | StateNotifierを継承したクラスのコンストラクター |
LocatorMixinのupdate | ref.watch()(*1) |
LocatorMixinのread | ref.read |
context.select | 未対応(*2) |
注1
LocatorMixinのupdateが実行されてもinitStateは実行されないが、ref.watch()が反応するとコンストラクターが呼ばれる(=作り直される)ので厳密には代わりになっていない。
注2
context.selectは未対応みたいです。(参照:https://github.com/rrousselGit/river_pod/issues/158)
このissueによれば、リッスンしたい値だけをref.watchするプロバイダーを作れば代替可能だそうです。
##最後に
間違い等ありましたら教えて下さい。