はじめに
Flutterは、シンプルなUI構築ができる強力なフレームワークですが、複雑なアプリケーションを構築する際には「状態管理」が重要なテーマになります。状態管理とは、アプリケーションの状態(データやUIの状態)を管理し、必要に応じて変更を適用することです。
本記事では、Flutterでの状態管理を簡単かつ効率的に行うために使用されるライブラリ、Providerについて解説します。初心者向けに、Providerを使った状態管理の基礎的な概念と実装方法をステップバイステップで説明します。
Providerとは?
Providerは、Googleが公式に推奨するFlutterの状態管理ライブラリの一つで、アプリケーションの状態(データやビジネスロジック)をシンプルに管理できるようにするものです。InheritedWidgetをベースにしており、下記のような特徴を持ちます。
Providerの特徴
- シンプルで使いやすい:公式サポートであり、ドキュメントも充実している。
- リビルドの効率化:必要な部分だけをリビルドするため、パフォーマンスに優れる。
- 柔軟な状態管理:グローバルな状態管理にも、局所的な状態管理にも対応可能。
Providerの導入手順
Providerのインストール
まず、ProviderをFlutterプロジェクトに追加する必要があります。pubspec.yamlファイルに以下を追加し、インストールを行います。
dependencies:
flutter:
sdk: flutter
provider: ^6.0.0その後、以下のコマンドでパッケージをインストールします。
flutter pub getProviderを使った基本的な実装
ここでは、簡単なカウンターアプリを使ってProviderの使い方を説明します。このアプリでは、ボタンを押すたびにカウントが増加し、その状態をProviderで管理します。
Providerの基本的な使い方
モデルクラスの作成
まず、アプリケーションの状態を管理するためのモデルクラスを作成します。ここでは、カウントの値を管理するCounterModelクラスを作成します。
ChangeNotifierを継承していることで、状態が変更された際にUI側へ通知を送ることができます。int get count => _count;- これは
getterメソッドです。外部のクラスやウィジェットが_countの値を取得できるようにしています。この方法で、_countに直接アクセスすることなく、安全にカウンターの値を取得できます。
- これは
notifyListeners()を呼び出すことで、Providerを介して依存しているウィジェットに再ビルドを促します。
import 'package:flutter/material.dart';
class CounterModel with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // 状態が変わったことを通知する
}
}
Providerで状態を管理
次に、main.dartファイルでProviderを使ってCounterModelをアプリ全体に提供します。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter_model.dart'; // モデルクラスのインポート
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CounterModel()),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CounterScreen(),
);
}
}
ChangeNotifierProviderを使って、CounterModelをアプリ全体に提供します。これにより、アプリ内のどこでもCounterModelにアクセスし、状態を操作することができるようになります。
UIに状態を反映する
次に、UI部分でCounterModelの状態を取得し、UIに反映させます。
Provider.of<T>(context)Providerを使用して、ツリー内のどこかで提供されたモデル(ここではCounterModel)を取得します。Tには、取得したいデータ型(ここではCounterModel)が指定されます。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter_model.dart';
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = Provider.of<CounterModel>(context);
return Scaffold(
appBar: AppBar(
title: Text('Provider Counter App'),
),
body: Center(
child: Text(
'Count: ${counter.count}',
style: TextStyle(fontSize: 40),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
counter.increment(); // カウントを増やす
},
child: Icon(Icons.add),
),
);
}
}ここでは、Provider.of<CounterModel>(context)を使って、CounterModelの状態にアクセスしています。ボタンを押すとincrementメソッドが呼ばれ、カウントが増加し、notifyListenersによってUIが再ビルドされます。
Providerの使い方を深める
Consumerを使った状態の取得
Provider.ofの代わりに、Consumerを使って状態を取得し、UIに反映させることもできます。Consumerは必要な箇所だけを再ビルドし、パフォーマンスを向上させます。
Consumer<CounterModel>は、Providerを利用してCounterModelの状態に依存しているウィジェットにデータを供給します。ここでは、Consumerを使って、CounterModelのcountプロパティの変化を監視し、Textウィジェットにその値を表示しています。builder: (context, counter, child)のcounterは、CounterModelのインスタンスです。このbuilder関数は、モデルの状態が変更されるたびに呼ばれます。
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Provider Counter App'),
),
body: Center(
child: Consumer<CounterModel>(
builder: (context, counter, child) {
return Text(
'Count: ${counter.count}',
style: TextStyle(fontSize: 40),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Provider.of<CounterModel>(context, listen: false).increment();
},
child: Icon(Icons.add),
),
);
}
}listen: false を使ってリビルドを防ぐ
Provider.ofで状態を取得する際、listen: falseオプションを使うことで、そのウィジェットがリビルドされることを防ぐことができます。たとえば、FloatingActionButtonが押されたときにカウントが増えるだけで、ボタン自体はリビルドしないようにする場合です。
Providerの応用:複数の状態を管理する
Providerを使って、複数の状態を管理することも簡単です。たとえば、カウンターに加えて、ユーザー情報を管理するための別のモデルを追加できます。
import 'package:flutter/material.dart';
class UserModel with ChangeNotifier {
String _name = "Guest";
String get name => _name;
void updateName(String newName) {
_name = newName;
notifyListeners();
}
}複数のChangeNotifierProviderを使って、これらの状態をアプリ全体に提供します。
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CounterModel()),
ChangeNotifierProvider(create: (_) => UserModel()),
],
child: MyApp(),
);
これにより、異なる画面やウィジェットで異なる状態にアクセスし、それぞれを管理することができます。
今回のサンプルコード
lib/counter_model.dart
import 'package:flutter/material.dart';
class CounterModel with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // 状態が変わったことを通知する
}
}
lib/main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter_model.dart'; // モデルクラスのインポート
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CounterModel()),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CounterScreen(),
);
}
}
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Provider Counter App'),
),
body: Center(
child: Consumer<CounterModel>(
builder: (context, counter, child) {
return Text(
'Count: ${counter.count}',
style: TextStyle(fontSize: 40),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Provider.of<CounterModel>(context, listen: false).increment();
},
child: Icon(Icons.add),
),
);
}
}まとめ
Providerは、Flutterでの状態管理を簡素化し、効率的に管理できる強力なツールです。この記事では、Providerの基本的な使い方や、ChangeNotifierを使った状態管理の実装、Consumerやlisten: falseを使ったパフォーマンス改善の方法を紹介しました。
この記事のポイント
- Providerを使った状態管理の導入と基本操作
ChangeNotifierを使って状態の変更を通知し、UIを再ビルドConsumerやlisten: falseでパフォーマンス最適化
初心者でも理解しやすいProviderの使い方を学んで、より複雑なFlutterアプリケーションの状態管理に役立ててください。今後は、さらに高度な状態管理パターン(例えば、RiverpodやReduxなど)にも挑戦してみてください!


コメント