RiverpodはStateNotifierのLocatorMixinをサポートしていない

# はじめに

[Provider](https://pub.dev/packages/provider)は、Flutterでの状態管理に使われる最もポピュラーなパッケージのひとつです。
[Riverpod](https://pub.dev/packages/riverpod)はこのProviderの改良版で、例えば以下のような点がProviderと違います。

- Provider使用時に出くわしがちな`ProviderNotFoundException`をコンパイル時に検査する
- Flutterのフレームワークに依存せずBuildContextなしにProviderをlistenできる
- FlutterのDevToolをデバッグに活用できる

[StateNotifier](https://pub.dev/packages/state_notifier)はValueNotifierのパフォーマンスやユーティリティに関して改良を加えたパッケージで、Providerとよく併用されます(Riverpodには同梱されています)。
LocatorMixinは、そのStateNotifierパッケージに含まれるMixinです。

> StateNotifier<T>継承クラス(HogeNotifierやHogeControllerなど)において、providerのProviderによってcontextに流されている外部サービスにアクセスする際に、Provider.of/context.read/context.watchを使用したくなると思います。
LocatorMixinをHogeNotifierにmixinすることで、これらのアクセスが簡単に実現できるようになります。具体的には、read/updateをHogeNotifier内で使用することができるようになります。

# RiverpodでLocatorMixinを使用すると...

RiverpodでLocatorMixinを使用した場合、コンパイルは通り例外も特にエラーもスローされませんが、**LocatorMixinの各メソッド(initState, updateなど)が呼ばれません。**
例えば以下の例では`initState`だけが呼ばれず、それ以外は普通に動作します。

```dart

final homeStateProvider = StateNotifierProvider((ref) => HomeStateNotifier());

class HomeStateNotifier extends StateNotifier<HomeState> with LocatorMixin {
  HomeStateNotifier() : super(const HomeState());

  @override
  void initState() {
    super.initState();
    logs('HomeStateNotifier init state');
    _loadTrending();
    _loadCategory();
    _loadPromotion();
    _loadNewServices();
  }

class TrendingVendor extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final result = useProvider(
        homeStateProvider.state.select((value) => value?.trendingResult));
    if (result == null) {
      return const CircleLoading();
    }
    if (result.isFail) {
      return FailWidget(result.message);
    }
```

# LocatorMixinではなくProviderReferenceを使う
LocatorMixinの`read`, `watch`ように別のProviderで提供されているインスタンスにアクセスしたい場合は、Riverpodの[ProviderReference](https://pub.dev/documentation/riverpod/latest/all/ProviderReference-class.html)を使うと便利です。


```dart

final userRepositoryProvider = Provider((ref) => UserRepository());

final userControllerProvider = StateNotifierProvider((ref) {
  return UserController(
    // userRepositoryProviderからUserRepositoryを取得してUserControllerを作成
    repository: ref.watch(userRepositoryProvider),
  );
});
```

```dart
final myLocalServiceProvider = StateProvider((ref) => MyLocalService());

final myStateNotifierProvider = StateNotifierProvider((ref) {
  final notifier = MyStateNotifier<();

  final removeListener = ref.watch(myLocalServiceProvider).addListener((state) {
    //MyLocalServiceが更新された
    notifier.onUpdateMyLocalService(state);
  });
  ref.onDispose(removeListener);

  return notifier;
});
```


また、ProviderReferenceをリポジトリに渡すとよりLocatorMixinライクに書くことができます。

```dart

final myLocalServiceProvider = Provider((ref) => MyLocalService());

final myChangeNotifierProvider = StateNotifierProvider((ref) => MyStateNotifier(ref));

class MyStateNotifier extends StateNotifier {
  MyStateNotifier(this.ref);

  final ProviderReference ref;

  int count = 43;

  void add() {
    count++;
    notifyListeners();
    ref.read(myLocalServiceProvider ).saveLocal(count);
  }

  void subtract() {
    count--;
    notifyListeners();
    ref.read(myLocalServiceProvider ).saveLocal(count);
  }
}
```

# 参考記事
- [【Flutter】state_notifierのLocatorMixinの便利な使い方](https://qiita.com/nukotsuka/items/f91dc5aca319b0da4dc2)
- [Document that flutte_state_notifier's LocatorMixin is unsupported](https://github.com/rrousselGit/river_pod/issues/75)