1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Riverpodのプロバイダの利用方法について説明してみた

Last updated at Posted at 2024-08-06

そもそもプロバイダってなに?

RiverPodの公式ドキュメントによると、

「プロバイダは Riverpod において中心的な役割を担っています。 プロバイダはあるステート(状態)をラップするためのオブジェクトであり、その監視を可能にしてくれます。」

とあります。要するに、プロバイダはアプリの色々な場所から、ステートの状態にアクセスできるようにしてくれるんです。

プロバイダの利用方法

プロバイダの作成

プロバイダの作成は基本的にグローバル変数として、宣言をしていきます。

final myProvider = Provider((ref) {
 return MyValue();
});
  • グローバルで宣言します。(プロバイダはイミュータブルなので、心配はないです。)
  • finalで宣言します。
  • 右辺のProviderで使用するプロバイダの種類を指定しています。他にも、FutureProviderStreamProviderなどの様々な種類のプロバイダがあるので、調べてみてください。

プロバイダ修飾子

 必要であれば、プロバイダ修飾子をつけてプロバイダを作成してください。

プロバイダ修飾子の種類
  • .autoDispose: プロバイダの監視が終わったタイミングで自動的にステートを破棄します。
  • .family : プロバイダ外部の値を用いて、プロバイダを作成できます。

以下、使用例です。

final myAutoDisposeProvider = StateProvider.autoDispose<int>((ref) => 0);

プロバイダの利用

refオブジェクトの取得

プロバイダからのref取得

プロバイダは全てrefオブジェクトを引数とします。

final provider = Provider((ref) {
  // `ref` を通じて他のプロバイダを利用する
  final repository = ref.watch(repositoryProvider);

  return SomeValue(repository);
})

このrefを渡す例は以下の通りです。

final countProvider = StateNotifierProvider<Count, int>((ref) {
  return Count(ref);
});

class Counter extends StateNotifier<int> {
  Counter(this.ref) : super(0);

  final Ref ref;

  void increment() {
    // Count は `ref` を使って他のプロバイダーを利用することができる
    final repository = ref.read(repositoryProvider);
  }
}

このようにすることでStateNotifierのCountrefを通して、別のプロバイダを利用可能になります。

ウィジェットからのref取得

通常のウィジェットはrefを取得できないので、Riverpodでは特別なウィジェットを用意しています。

  • StatelessWidget → ConsumerWidget
  • StatefulWidget (State) → ConsumerStatefulWidget (ConsumerState)
  • HookWidget → HookConsumerWidget (flutter_hooksを使用している場合)

ref.watch

プロバイダか、ウィジェットの中で、ref.watchを用いて、プロバイダを監視することができます。実際のところ、ref.watchでは値の変化に応じて、ウィジェットやプロバイダを変化させます。

以下はウィジェット内で、ref.watchを使って、プロバイダの値が変わるたびに画面を更新させる処理の例です。

final counterProvider = StateProvider((ref) => 0);

class HomeView extends ConsumerWidget {
  const HomeView({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // `ref` を使ってプロバイダを監視する
    final counter = ref.watch(counterProvider);

    return Text('$counter');
  }
}

今回の場合、カウンターの数を値として管理するプロバイダを監視しており、プロバイダの値が変化すると、ウィジェットが更新されて、変化後の値で画面が作られます。

ref.listen

ref.listenはエラー発生時のモーダル表示などの、変化に応じた処理をするときに使えます。
ref.listenメソッドは2つの引数を持っています。第一引数はプロバイダ、第二引数はステートが変化したときに実行されるコールバック関数を呼び出した際に、プロバイダの変更前後のステートの値が渡され、それぞれを使用できます。

以下のプロバイダ内で使用した例です。

final counterProvider = StateNotifierProvider<Counter, int>(Counter.new);

final anotherProvider = Provider((ref) {
  ref.listen<int>(counterProvider, (int? previousCount, int newCount) {
    print('The counter changed $newCount');
  });
  // ...
});

また、ref.listenはウィジェットのbuildメソッド内で使用できます。


final counterProvider = StateNotifierProvider<Counter, int>(Counter.new);

class HomeView extends ConsumerWidget {
  const HomeView({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    ref.listen<int>(counterProvider, (int? previousCount, int newCount) {
      print('The counter changed $newCount');
    });
    
    return Container();
  }
}

ref.read

ref.readメソッドを使うことでプロバイダの現在のステートを取得できます。ref.readはユーザの操作によって呼び出される関数内で使用することができる。


final counterProvider = StateNotifierProvider<Counter, int>(Counter.new);

class HomeView extends ConsumerWidget {
  const HomeView({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // `Counter` クラスの `increment()` メソッドを呼び出す
          ref.read(counterProvider.notifier).increment();
        },
      ),
    );
  }
}

このようにプロバイダを用いて、ステータスにアクセスしましょう。
弊社のFlutterアプリでもRiverpodアーキテクチャによく使われるこれらプロバイダを用いて、状態管理をしています。

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?