provider -> riverpod　移行ガイド

##追記
**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のオブジェクトに。

これがでかい。

その他の変更点は、その副作用と言っても良い。(と思っている)


```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のジェネリクスが必要になりました**

```dart
//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が出来ます。
例えば

```dart
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関数の引数にプロバイダーを入れて使います。

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


##最後に

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