torikatsu.dev

Flutterとかプログラミングとかガジェットとか書きます

【Flutter】RivderpodのStateNotifierがoverrideWithProviderできるようになっていた

こんにちは、とりかつ(@torikatsu923)です。

RiverpodでScopedProviderを使わなくてもStateNotifierをoverrideできるようになっていました。 今回はStateNotifierをoverrideする方法について紹介します。

今までのStateNotifier.family

以前以下のような記事を書きました。 torikatsu923.hatenablog.com

この記事では StateNotifierFamily を用いてStateNotifierの初期値を設定していました。 そして、初期値を設定したStateNotifierをウィジェットツリーから利用するために以下のようなコードを書く必要がありました。

このコードでやっていることは以下のとおりです。

  1. StateNotifier.family( providerFamily )を定義する (最終的にウィジェットツリーから利用したいStateNotifier)
  2. 初期値を設定したproviderFamilyをprovideするめに利用するScopedProvider( provider )を定義する
  3. ProviderScopeで生成した providerFamily を、 provider をoverrideすることで子ウィジェットから利用可能にする

provider定義側

final provider =
    ScopedProvider<StateNotifierProvider<SomeStateNotifier, SomeState>>(
        (ref) => throw Error());

final providerFamily = 
    StateNotifierProvider.family<SomeStateNotifier, SomeState, String>(
        (ref, text) => SomeStateNotifier(text: text));

なんらかのウィジェット

      // ...
      return ProviderScope(
        overrides: [
          provider
              .overrideAs((watch) => providerFamily(text)),
        ],

ところがRiverpod 1.0.0で以下のような変更が入っていました。

All providers can now be scoped. Breaking: ScopedProvider is removed. To migrate, change ScopedProviders to Providers.

pub.dev

ScopedProviderが撤廃されて、全てのProviderが overrideWithProvider することが可能になりました。

これによって上と同じことを以下のコードで実現できるようになりました。

provider定義側

final provider = StateNotifierProvider<SomeStateNotifier, SomeState>(
        (ref) => throw Error());

final providerFamily = 
    StateNotifierProvider.family<SomeStateNotifier, SomeState, String>(
        (ref, text) => SomeStateNotifier(text: text));

なんらかのウィジェット

      // ...
      return ProviderScope(
        overrides: [
          provider.overrideWithProvider(providerFamily("some text")),
        ],

StateNotifierをoverrideできると嬉しいこと

Providerをoverrideするためのコードは大きく変化しているようには見えません。

では、この変更がどういう時に嬉しいのでしょうか。 この変更はWidgetRef経由でStateNotifierを利用する際にとても便利になります。

従来のScopedProviderを利用する場合は、StateNotifierへアクセスするために以下のようにする必要がありました。

ref.read(ref.read(provider))

ScopedProviderによってprovideされるproviderをread する必要があったため ref.read を二重にしています。大したことないように見えますが、実装を進めていくと毎回二重に ref.read をするのは結構面倒でした。

これがアップデートによって ref.read が一回で済むようになりました。

ref.read(provider)

二重に ref.read する手間を省ける上に、StateNotifier.familyを利用してもStateNotifierと同じように利用できる点がとても便利になりました。