2023年4月30日
開発環境
OS:Windows 11
SDK:VS Code + flutter 3.7.5
パッケージとは
Flutterで実装するうえでかかせないのがパッケージです。
Flutterのベース機能はUIに特化されているため、アプリの機能性、操作性を拡張させるような実装を行うにはパッケージをインストールする必要があります。
Webを表示させたい、画像を表示させたい、データ管理を行いたい、など、
ベースロジックで対応しきれない場合は、Pub.devから適切なパッケージを探し、インストールします。
今回は状態管理を行うパッケージ、Riverpodを利用してアプリを作ります。
パッケージをインストールする
インストール手順は簡単です。
コマンドプロンプト(ターミナル)でパッケージ(flutter_riverpod)をインストールしたい当該プロジェクトフォルダに移動し、下記コマンドを実行します。
flutter pub add flutter_riverpod

プロジェクトにパッケージがインストールされます。
パッケージはpubspec.yamlで管理されており、yamlファイル内に指定したパッケージが追加されます。

逆にpubspec.yamlにインストールしたいパッケージを追記し、下記コマンドを実行してもパッケージをインストールすることができます。
flutter pub get
実装してみる
flutter create test2で作成したサンプルプログラムをRiverpodで置き換えてみます。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final countProvider = StateProvider((ref) => 0);
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends ConsumerWidget {
const MyHomePage({super.key, required this.title});
final String title;
void _incrementCounter(WidgetRef ref) {
ref.read(countProvider.notifier).state++;
}
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
ref.watch(countProvider).toString(),
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {_incrementCounter(ref);},
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
まずパッケージを使用するためにパッケージをimportします。
Riverpodを適用するためのポイントは3点です。
1)ProviderScopeで適用範囲とするクラスを指定する
2)StatefulWidget → CunsumerWidget へ置き換える
3)buildの引数にWidgetRefを追加する
あとはStateProviderを定義して参照、更新します。
値を参照する ref.read(定義名).state
値を参照する(更新検知) ref.watch(定義名).state
値を更新する ref.read(定義名.notifier).state = 更新値
実行すると下記のようになりました。
setStateを使用したサンプルプログラムと同じ動きになります。

またRiverpodの優れた点は別ページに遷移しても変わらず参照できる点です。
下記のようにページ遷移を実装します。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:test2/pages/nextpage.dart';
final countProvider = StateProvider((ref) => 0);
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends ConsumerWidget {
const MyHomePage({super.key, required this.title});
final String title;
void _incrementCounter(WidgetRef ref) {
ref.read(countProvider.notifier).state++;
}
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
ref.watch(countProvider).toString(),
style: Theme.of(context).textTheme.headlineMedium,
),
ElevatedButton(onPressed: (){Navigator.push(context, MaterialPageRoute(builder: (context) => const NextPage()));}, child: const Text('next'))
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {_incrementCounter(ref);},
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:test2/main.dart';
class NextPage extends ConsumerWidget {
const NextPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: const Text("next page"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times on Main page:',
),
Text(
ref.watch(countProvider).toString(),
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),// This trailing comma makes auto-formatting nicer for build methods.
);
}
}
実行すると下記となります。


次ページにおいてもメイン画面の値を参照できます。
ちなみに複雑な状態管理を行うにはStateNotifierProviderを使用します。
今回は以上です。