👻

【Flutter】riverpod_generator 動作確認用コードサンプル

2023/01/21に公開約12,400字

Riverpod の各プロバイダのサポート状況

「Riverpod の各プロバイダ」の 「riverpod_generator でのサポート状況」について、表にまとめます。2023/01/21 時点。

No. プロバイダ サポート状況 備考
1 Provider サポート済
2 NotifierProvider サポート済
3 AsyncNotifierProvider サポート済
4 StateNotifierProvider まだ未サポート? (Async)NotifierProvider で代替?
5 FutureProvider サポート済
6 StreamProvider まだ未サポート? サポート対応中?
7 StateProvider サポートしない? [1]
8 ChangeNotifierProvider まだ未サポート? (Async)NotifierProvider で代替?

各プロバイダの動作確認用コードサンプル

Provider

Provider

test/riverpod_generator/provider_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'provider_test.g.dart';


String Function(String s) hello(HelloRef ref) {
  String hello(String s) {
    return "Hello World $s";
  }

  return hello;
}


String Function(String s) helloF(HelloRef ref, {required String init}) {
  String hello(String s) {
    return "$init $s";
  }

  return hello;
}

void main() {
  group("basic", () {
    test("Provider", () {
      final container = ProviderContainer();

      expect(helloProvider, isA<AutoDisposeProvider>());

      final hello = container.read(helloProvider);

      expect(hello("add"), "Hello World add");
    });
  });

  group("family", () {
    test("Provider", () {
      final container = ProviderContainer();

      expect(helloFProvider, isA<HelloFFamily>());

      final hello = container.read(helloFProvider(init: "Hello World"));

      expect(hello("add"), "Hello World add");
    });
  });
}
NotifierProvider

NotifierProvider

test/riverpod_generator/notifier_provider_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'notifier_provider_test.g.dart';


class HelloNotifier extends _$HelloNotifier {
  
  String build() {
    return "Hello World";
  }

  void add(String s) {
    state = "$state $s";
  }
}


class HelloNotifierF extends _$HelloNotifierF {
  
  String build({required String init}) {
    return init;
  }

  void add(String s) {
    state = "$state $s";
  }
}

void main() {
  group("basic", () {
    test("NotifierProvider build", () {
      final container = ProviderContainer();

      expect(helloNotifierProvider, isA<AutoDisposeNotifierProvider>());
      expect(container.read(helloNotifierProvider), "Hello World");
    });

    test("NotifierProvider add", () {
      final container = ProviderContainer();

      expect(helloNotifierProvider, isA<AutoDisposeNotifierProvider>());
      expect(container.read(helloNotifierProvider), "Hello World");

      container.read(helloNotifierProvider.notifier).add("add");
      expect(container.read(helloNotifierProvider), "Hello World add");
    });
  });

  group("family", () {
    test("NotifierProvider build", () {
      final container = ProviderContainer();

      expect(helloNotifierFProvider, isA<HelloNotifierFFamily>());
      expect(container.read(helloNotifierFProvider(init: "Hello World")),
          "Hello World");
    });

    test("NotifierProvider add", () {
      final container = ProviderContainer();

      expect(helloNotifierFProvider, isA<HelloNotifierFFamily>());
      expect(container.read(helloNotifierFProvider(init: "Hello World")),
          "Hello World");

      container
          .read(helloNotifierFProvider(init: "Hello World").notifier)
          .add("add");

      expect(container.read(helloNotifierFProvider(init: "Hello World")),
          "Hello World add");
    });
  });
}

AsyncNotifierProvider

AsyncNotifierProvider

test/riverpod_generator/async_notifier_provider_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'async_notifier_provider_test.g.dart';


class HelloAsyncNotifier extends _$HelloAsyncNotifier {
  
  Future<String> build() {
    return Future.value("Hello AsyncNotifier");
  }

  void add(String s) async {
    state = const AsyncLoading();
    state = await AsyncValue.guard(() => Future.value("${state.value} $s"));
  }
}


class HelloAsyncNotifierF extends _$HelloAsyncNotifierF {
  
  Future<String> build({required String init}) {
    return Future.value(init);
  }

  void add(String s) async {
    state = const AsyncLoading();
    state = await AsyncValue.guard(() => Future.value("${state.value} $s"));
  }
}

void main() {
  group("basic", () {
    test("AsyncNotifierProvider build", () async {
      final container = ProviderContainer();

      expect(
          helloAsyncNotifierProvider, isA<AutoDisposeAsyncNotifierProvider>());

      expect(container.read(helloAsyncNotifierProvider), isA<AsyncLoading>());

      // AsyncLoding から AsyncDataになるのを待つ
      await Future<void>.value();

      expect(
          container.read(helloAsyncNotifierProvider), isA<AsyncData<String>>());
      expect(container.read(helloAsyncNotifierProvider).value,
          "Hello AsyncNotifier");
    });
    test("AsyncNotifierProvider add", () async {
      final container = ProviderContainer();

      expect(
          helloAsyncNotifierProvider, isA<AutoDisposeAsyncNotifierProvider>());

      expect(container.read(helloAsyncNotifierProvider), isA<AsyncLoading>());

      await Future<void>.value();

      expect(
          container.read(helloAsyncNotifierProvider), isA<AsyncData<String>>());
      expect(container.read(helloAsyncNotifierProvider).value,
          "Hello AsyncNotifier");

      container.read(helloAsyncNotifierProvider.notifier).add("add");

      expect(container.read(helloAsyncNotifierProvider), isA<AsyncLoading>());

      // AsyncLoding から AsyncDataになるのを待つ
      await Future<void>.value();

      expect(
          container.read(helloAsyncNotifierProvider), isA<AsyncData<String>>());
      expect(container.read(helloAsyncNotifierProvider).value,
          "Hello AsyncNotifier add");
    });
  });

  group("family", () {
    test("AsyncNotifierProvider build", () async {
      final container = ProviderContainer();

      expect(helloAsyncNotifierFProvider, isA<HelloAsyncNotifierFFamily>());

      expect(
          container
              .read(helloAsyncNotifierFProvider(init: "Hello AsyncNotifier")),
          isA<AsyncLoading>());

      // AsyncLoding から AsyncDataになるのを待つ
      await Future<void>.value();

      expect(
          container
              .read(helloAsyncNotifierFProvider(init: "Hello AsyncNotifier")),
          isA<AsyncData<String>>());

      expect(
          container
              .read(helloAsyncNotifierFProvider(init: "Hello AsyncNotifier"))
              .value,
          "Hello AsyncNotifier");
    });

    test("AsyncNotifierProvider add", () async {
      final container = ProviderContainer();

      expect(helloAsyncNotifierFProvider, isA<HelloAsyncNotifierFFamily>());

      expect(
          container
              .read(helloAsyncNotifierFProvider(init: "Hello AsyncNotifier")),
          isA<AsyncLoading>());

      await Future<void>.value();

      expect(
          container
              .read(helloAsyncNotifierFProvider(init: "Hello AsyncNotifier")),
          isA<AsyncData<String>>());

      expect(
          container
              .read(helloAsyncNotifierFProvider(init: "Hello AsyncNotifier"))
              .value,
          "Hello AsyncNotifier");

      container
          .read(
              helloAsyncNotifierFProvider(init: "Hello AsyncNotifier").notifier)
          .add("add");

      expect(
          container
              .read(helloAsyncNotifierFProvider(init: "Hello AsyncNotifier")),
          isA<AsyncLoading>());

      // AsyncLoding から AsyncDataになるのを待つ
      await Future<void>.value();

      expect(
          container
              .read(helloAsyncNotifierFProvider(init: "Hello AsyncNotifier")),
          isA<AsyncData<String>>());
      expect(
          container
              .read(helloAsyncNotifierFProvider(init: "Hello AsyncNotifier"))
              .value,
          "Hello AsyncNotifier add");
    });
  });
}

FutureProvider

FutureProvider

test/riverpod_generator/future_provider_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'future_provider_test.g.dart';


Future<String> helloFuture(HelloFutureRef ref) {
  return Future.value("Hello Future");
}


Future<String> helloFutureF(HelloFutureFRef ref, {required String init}) {
  return Future.value("Hello Future");
}

void main() {
  group("basic", () {
    test("FutureProvider", () async {
      final container = ProviderContainer();

      expect(helloFutureProvider, isA<AutoDisposeFutureProvider>());
      expect(container.read(helloFutureProvider), isA<AsyncLoading>());

      // AsyncLoding から AsyncDataになるのを待つ
      await Future<void>.value();

      expect(
        container.read(helloFutureProvider),
        isA<AsyncData<String>>().having((s) => s.value, "", "Hello Future"),
      );

      expect(container.read(helloFutureProvider).value, "Hello Future");
    });
  });

  group("family", () {
    test("FutureProvider", () async {
      final container = ProviderContainer();

      expect(helloFutureFProvider, isA<HelloFutureFFamily>());
      expect(container.read(helloFutureFProvider(init: "Hello Future")),
          isA<AsyncLoading>());

      // AsyncLoding から AsyncDataになるのを待つ
      await Future<void>.value();

      expect(
        container.read(helloFutureFProvider(init: "Hello Future")),
        isA<AsyncData<String>>().having((s) => s.value, "", "Hello Future"),
      );

      expect(container.read(helloFutureFProvider(init: "Hello Future")).value,
          "Hello Future");
    });
  });
}

その他

非 AutoDispose 化

keepAlivetrueを指定すると、非 AutoDispose になるようです。

-    @riverpod
+    @Riverpod(keepAlive: true)

build.yaml

test/riverpod_generator/配下でコード生成するために設定しました。

build.yaml
targets:
  $default:
    sources:
      include:
        - $package$
        - pubspec.yaml
        - lib/**
        - test/riverpod_generator/**

思ったことメモ

  • StateProvider は、これまで StateNotifierProvider で代替可能だったように、今後は、(Async)NotifierProvider でも代替可能だと思われます。一方で、StateProvider は、class 定義せずに気軽に使える点にメリットを感じているため、代替せずに利用継続していくのも良いのではと思いました。

  • プロバイダが自動生成されるため、例えば、「NotifierProvieder の class 定義」と、その class 定義から「自動生成されるプロバイダのインスタンス」が、1:1 になるように思われる。
    1:多、になるようにプロバイダのインスタンスを複数生成したい場合(この場合があるのか?)、どうやるか?

脚注
  1. StateProvider は十分シンプルなため、ジェネレータで自動生成する必要が無いため、サポートしない?。 ↩︎

Discussion

ログインするとコメントできます