LoginSignup
36
26

More than 1 year has passed since last update.

provider -> riverpod 移行ガイド

Last updated at Posted at 2021-01-12

追記

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するプロバイダーを作れば代替可能だそうです。

最後に

間違い等ありましたら教えて下さい。

36
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
26