はじめに
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 get
Providerを使った基本的な実装
ここでは、簡単なカウンターアプリを使って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など)にも挑戦してみてください!
コメント