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

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

StateProviderを使えばシンプルなデータを取得、外部からデータを変更できます。複雑なデータ(複数のプロパティやメソッドを使用)を扱う場合にはStateNotifierProviderが使用されます。

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

目次

事前準備|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をラップする必要があります。

StateProviderの使い方

定義

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

StateProviderは全ての型の値を返り値にできます。

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

データ取得

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: Text(
            count.toString(),
            style: TextStyle(fontSize: 30),
          ),
        ),
      ),
    );
  }
}

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

final count = ref.watch(counterProvider);

ref.watchStateProviderの値を取得します。またStateProviderの状態(値)を監視し、状態が更新する度にビルドし直します。

Consumerでデータ取得

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

StateProviderのデータを外部から更新

StateProviderでデータを更新する方法は主に2つあります。

1つは直近のデータを元にデータ更新する方法、もう1つは直近のデータを無視してデータ更新する方法です。

直近のデータ(状態)を元に更新

ref.read(counterProvider.notifier).update((state) => ++state);
IconButton(
  icon: Icon(Icons.add),
  onPressed: () => ref.read(counterProvider.notifier).update((state) => ++state),
),

カウンターアプリのプラスボタンやマイナスボタンなど直近のデータを元に新しいデータを算出し更新するにはupdate()を使用します。

直近のデータ(状態)を無視して更新

ref.read(counterProvider.notifier).state = 0;
ElevatedButton(
  onPressed: () {
    ref.read(counterProvider.notifier).state = 0;
  },
  child: Text('Reset'),
)

カウンターアプリのリセットボタンなど直近のデータを無視してデータを更新する場合にはstateでデータを取得し新しいデータを代入します。

サンプルコード

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

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

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: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  IconButton(
                    icon: Icon(Icons.remove),
                    onPressed: () => ref.read(counterProvider.notifier).update((state) => ++state),
                  ),
                  Text(
                    count.toString(),
                    style: TextStyle(fontSize: 30),
                  ),
                  IconButton(
                    icon: Icon(Icons.add),
                    onPressed: () => ref.read(counterProvider.notifier).update((state) => ++state),
                  ),
                ],
              ),
              ElevatedButton(
                onPressed: () {
                  ref.read(counterProvider.notifier).state = 0;
                },
                child: Text('Reset'),
              )
            ],
          ),
        ),
      ),
    );
  }
}

一緒に読みたい

参考

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