flutter_riverpod学んでみる。


今流行りの状態管理について学んでみる。

公式ドキュメント
https://riverpod.dev/ja/
pub.devのリンク
https://pub.dev/packages/flutter_riverpod/versions/0.14.0+3/example

StateProviderって何だ?

pub.devのExampleに書いてあるStateProviderについて調べてみた。

(外部から)変更可能な値を公開できるProviderらしい???

riverpodに詳しい方によれば、「現在選択されているアイテムやフィルタリングの状態など、単純な状態を保持するのに適しています。
他のProviderと組み合わせたり、複数の画面からアクセス可能です。」とのこと。
どういうこと?

先ずはコードを書いてみた。
フォルダ構成(mvvmぽくしなくてもいいかも...)

lib
├── main.dart
├── models
│   └── model.dart
└── views
    └── home_page.dart

models/model.dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
// StateProviderの宣言
// Providerの定数をグローバルに宣言
final counterProvider = StateProvider((ref) => 0);
final appNameProvider = StateProvider((ref) => 'flutter_riverpod!');
final personNameProvider = StateProvider((ref) => 'Jboy Hasimoto');
final petNameProvider = StateProvider((ref) => 'ボナパルト???');

グローバルに宣言っていうのが、どのプログラミング言語でもどこからでもアクセスできるものだったような?
ローカルスコープっていうのが、{}のなか関数の中でしか使えないやつがあった...
これ、クラスで書いてないよ...
今回は必要なし。

Widgetで使用する
views/home_page.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mvvm_sample/models/model.dart';

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.indigo,
        title: const Text('flutter_riverpod')),
      body: Center(
        child: Column(
          // 画面中を寄せる
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            _countMethod(),
            const SizedBox(
              height: 20,
            ),
            _appName(),
            const SizedBox(
              height: 20,
            ),
            _personName(),
            const SizedBox(
              height: 20,
            ),
            _petName(),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.read(counterProvider).state++,
        child: const Icon(Icons.add),
      ),
    );
  }

  Widget _countMethod() {
    return Consumer(builder: (context, watch, _) {
      final count = watch(counterProvider).state;
      return Text(
        '$count',
        style: TextStyle(
            fontSize: 30, fontWeight: FontWeight.bold, color: Colors.red),
      );
    });
  }

  Widget _appName() {
    return Consumer(builder: (context, watch, _) {
      final appName = watch(appNameProvider).state;
      return Text(
        '${appName}',
        style: TextStyle(
          fontSize: 20,
          fontWeight: FontWeight.bold,
          color: Colors.indigo,
        ),
      );
    });
  }

  Widget _personName() {
    return Consumer(builder: (context, watch, _) {
      final personName = watch(personNameProvider).state;
      return Text(
        '${personName}',
        style: TextStyle(
          fontSize: 20,
          fontWeight: FontWeight.bold,
          color: Colors.green,
        ),
      );
    });
  }

  Widget _petName() {
    return Consumer(builder: (context, watch, _) {
      final petName = watch(petNameProvider).state;
      return Text(
        '${petName}',
        style: TextStyle(
          fontSize: 20,
          fontWeight: FontWeight.bold,
          color: Colors.black87,
        ),
      );
    });
  }
}

main.dart

import 'package:flutter/material.dart';
// 使用するライブラリーのflutter_riverpod.dartをimportする
import 'package:flutter_riverpod/flutter_riverpod.dart';
// viewsのページを読み込む
import 'package:mvvm_sample/views/home_page.dart';

void main() {
  runApp(
    // Providerのスコープを定義
    const ProviderScope(child: MyApp()),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home());
  }
}

iPhoneのシュミレーターでbuildしてみる。