【Flutter/Riverpod】ChangeNotifierProviderで状態管理|外部からデータ変更可能

今回はRiverpodのChangeNotifierProviderを使った状態管理を行なっていきます。

ChangeNotifierProviderを使用するにはChangeNotifierを継承したクラスを定義する必要があります。外部からデータを変更するにはChangeNotifierを継承したクラスのメソッドを使用します。

\ 世界最大級のオンライン学習サービス /

目次

事前準備|flutter_riverpodの導入

flutter pub add flutter_riverpod
import 'package:flutter_riverpod/flutter_riverpod.dart';

flutter_riverpodを導入します。

ProviderScopeでウィジェットツリーをラップ

void main() => runApp(ProviderScope(child: MyApp()));

Riverpodのプロバイダを使用するにはProviderScopeでウェジェットツリーのルート(先祖)となるWidgetをラップする必要があります。

ChangeNotifierProviderの使い方

ChangeNotifierを継承したクラスの定義

class CounterNotifier extends ChangeNotifier {
  int _count = 0;

  void add() {
    _count++;
    notifyListeners();
  }

  void subtract() {
    _count--;
    notifyListeners();
  }
}

まずはChangeNotifierを継承したクラスを定義します。

ChangeNotifierを継承したクラスでメソッドを定義する際の注意点として、オブジェクトに変更を加える処理を書いたらnotifyListenersを呼び出す必要があります。

ChangeNotifierProviderの定義

final counterProvider = ChangeNotifierProvider(
  (ref) => CounterNotifier(),
);

ChangeNotifierProviderChangeNotifierを継承したクラスを返り値に取ります。

今回はグローバル変数として定義しています。(記事下にサンプルコードあり)

データ取得

class MyApp extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('FlutterZero')),
        body: Center(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              IconButton(
                icon: Icon(Icons.remove),
                onPressed: () => count.subtract(),
              ),
              Text(
                count._count.toString(),
                style: TextStyle(fontSize: 30),
              ),
              IconButton(
                icon: Icon(Icons.add),
                onPressed: () => count.add(),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

StatelessWidgetでプロバイダの値を取得したい場合はConsumerWidgetを継承します。StatefulWidgetの場合はConsumerStatefulWidgetを継承します。

final count = ref.watch(counterProvider);

ref.watchChangeNotifierProviderで返り値として指定したChangeNotifierを継承したクラスをオブジェクト化します。

ChangeNotifierを継承したクラスのメソッドが使用されnotifyListenersが呼び出される度にビルドし直します。

外部からデータを変更

Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    IconButton(
      icon: Icon(Icons.remove),
      onPressed: () => count.subtract(),
    ),
    Text(
      count._count.toString(),
      style: TextStyle(fontSize: 30),
    ),
    IconButton(
      icon: Icon(Icons.add),
      onPressed: () => count.add(),
    ),
  ],
),

ChangeNotifierを継承したクラスのメソッドを使用して値(プロパティの値)を変更できます。

Consumerでデータ取得

ConsumerWidgetまたはConsumerStatefulWidgetを継承せずにConsumerで値を取得することも可能です。

サンプルコード

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class CounterNotifier extends ChangeNotifier {
  int _count = 0;

  void add() {
    _count++;
    notifyListeners();
  }

  void subtract() {
    _count--;
    notifyListeners();
  }
}

final counterProvider = ChangeNotifierProvider(
  (ref) => CounterNotifier(),
);

void main() => runApp(ProviderScope(child: MyApp()));

class MyApp extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('FlutterZero')),
        body: Center(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              IconButton(
                icon: Icon(Icons.remove),
                onPressed: () => count.subtract(),
              ),
              Text(
                count._count.toString(),
                style: TextStyle(fontSize: 30),
              ),
              IconButton(
                icon: Icon(Icons.add),
                onPressed: () => count.add(),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

一緒に読みたい

参考

  • URLをコピーしました!
目次