【Flutter】StateNotifierProviderで状態管理(Riverpod)

flutter

1. 概要

上記前回のブログでは「Riverpod」の「StateProvider」を使ったCounterの状態管理についてでした。

「StateProvider」は「enumや数値」などシンプルなステートを管理するのに適しているようです。

StateProvider は外部から変更が可能なステート(状態)を公開するプロバイダです。 StateNotifierProvider の簡易版であり、ステートの管理にわざわざ StateNotifier クラスを定義するほどではない場合にご利用いただけます。

https://riverpod.dev/ja/docs/providers/state_provider

今回は「StateNotifierProvider」を使い、Counterの状態管理をする内容についてです。

今回も前回と結果は同じでシンプルなステートを管理する内容なので、結果的には「StateProvider」を使った方が良いと思われますが、ここでは「StateNotifierProvider」を使って開発する例として見て頂ければと思います。

StateNotifierProvider は StateNotifier(Riverpod が依存する state_notifier パッケージのクラス)を監視し、公開するためのプロバイダです。 この StateNotifierProvider および StateNotifier は、ユーザ操作などにより変化するステート(状態)を管理するソリューションとして Riverpod が推奨するものです。

https://riverpod.dev/ja/docs/providers/state_notifier_provider

※今回は下記の例で、前回と同じ結果になるように構成してます。

  • Riverpod
    • StatelessWidget / ConsumerWidget
      • アプリ起動中に状態が変化しない
      • StateNotifierProvider / ProviderScope

対象としては開発を1年程やってて自分で最初から開発してみたい方になります。そのため細かい用語などの説明はしません。

2. StateNotifierProvider

2-1. プロジェクトを作成

2-2. Dependencyのインストール

flutter pub add flutter_riverpod
dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  flutter_riverpod: ^1.0.4

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^2.0.0

2-3. ソースコード

  • main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_demo_with_model/models/counter.dart';
import 'package:riverpod_demo_with_model/notifiers/counter_notifier.dart';
import 'package:riverpod_demo_with_model/views/home.dart';

final counterProvider =
    StateNotifierProvider<CounterNotifier, CounterData>((ref) {
  return CounterNotifier();
});

void main() {
  runApp(const ProviderScope(
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

  • views/home.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_demo_with_model/main.dart';

class MyHomePage extends ConsumerWidget {
  const MyHomePage({Key? key, required String title}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final data = ref.watch(counterProvider);
    final counterNotifier = ref.read(counterProvider.notifier);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Riverpod example'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          const Text('You have pushed the button this many times:'),
          Center(
            child: Text(
              data.counter.toString(),
              style: Theme.of(context).textTheme.headline4,
            ),
          ),
          ElevatedButton(
              onPressed: () => counterNotifier.plus(), child: const Text('+')),
          ElevatedButton(
              onPressed: () => counterNotifier.minus(), child: const Text('-')),
        ],
      ),
    );
  }
}

  • models/counter.dart
import 'package:flutter/material.dart';

@immutable
class CounterData {
  const CounterData({required this.counter});
  final int counter;
}

  • notifiers/counter_notifier.dart
// ignore_for_file: avoid_print

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_demo_with_model/models/counter.dart';

class CounterNotifier extends StateNotifier<CounterData> {
  CounterNotifier() : super(const CounterData(counter: 0));

  void plus() {
    state = CounterData(counter: state.counter + 1);
    print('plus=${state.counter}');
  }

  void minus() {
    state = CounterData(counter: state.counter - 1);
    print('minus=${state.counter}');
  }
}

2-4. 結果

2-5. 解説

「ProviderScope」を使い、状態管理の対象を指定します。

状態を管理するためのプロバイダとして「StateNotifierProvider」を使います。

プロバイダを利用するためには「ref」を取得する必要があるので「ConsumerWidget」を継承します。

  • プロバイダの利用方法 | Riverpod
    • ref.watch():プロバイダの値を取得した上で、その変化を監視する。値が変化すると、その値に依存するウィジェットやプロバイダの更新が行われる。
    • ref.read():プロバイダの値を取得する(監視はしない)。クリックイベント等の発生時に、その時点での値を取得する場合に使用できる。

3. 参考

投稿者プロフィール

Sondon
開発好きなシステムエンジニアです。
卓球にハマってます。

関連記事

  1. flutter

    【Flutter】Flutter実装メモ showModalBotto…

  2. flutter

    【Flutter】画面が開く前にローディングを表示

  3. flutter

    【Flutter】Pankoに「みんなで割り勘」機能を追加

  4. flutter

    【Flutter】アプリにAdmobバナー広告を設置

  5. flutter

    【Flutter】FlutterとKotlinでそれぞれCounter…

  6. flutter

    【Flutter】Demoプロジェクトの値の状態を管理(Flutter…

最近の記事

  1. React
  2. 日記アプリ第3回
  3. 日記アプリ第2回
  4. 日記アプリ第1回

制作実績一覧

  1. Vivaya
  2. Checkeys