12
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-12-05

はじめに

Providerは、Flutterでの状態管理に使われる最もポピュラーなパッケージのひとつです。
RiverpodはこのProviderの改良版で、例えば以下のような点がProviderと違います。

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

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

StateNotifier継承クラス(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だけが呼ばれず、それ以外は普通に動作します。


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を使うと便利です。


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

final userControllerProvider = StateNotifierProvider((ref) {
  return UserController(
    // userRepositoryProviderからUserRepositoryを取得してUserControllerを作成
    repository: ref.watch(userRepositoryProvider),
  );
});
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ライクに書くことができます。


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);
  }
}

参考記事

12
4
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
12
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?