Flutter Providerを使ったシンプルな状態管理
はじめに
Flutterでアプリを作るとき、UIを更新するタイミングやデータの受け渡しが多くなる場面はありませんか。
画面を切り替えたり、フォーム入力内容を別の画面で活用したりする場合、状態管理が必要になってくるでしょう。
FlutterにはsetStateを使う方法や、Reduxなどさまざまな方法がありますが、比較的わかりやすいのがProviderというパッケージです。
このProviderを使うと、アプリの複数Widget間でデータを手軽に共有できるようになります。
今回は、初心者の方でも理解できるように、Providerの基本から導入手順、具体的な使い方までを紹介してみます。
この記事を読むとわかること
Flutterでよく利用されるProviderとは何か、その概要がわかります。
また、なぜProviderが状態管理に向いているのか、導入手順やコード例を交えて学ぶことができます。
さらに、実務で遭遇しがちなシーンを例にとり、どのようにProviderを活用できるかをイメージできるようになるでしょう。
Flutter Provider とは
Flutter Providerは、Widget間でデータを共有したいときに利用するパッケージです。
状態管理をシンプルに実装できるように設計されており、画面遷移が多いアプリやリアルタイムでのデータ更新が必要なアプリでも使いやすいという特徴があります。
Widgetツリーの上位にProviderを配置してデータを保持し、必要な箇所でそのデータを取得・変更する仕組みです。
これによって、深い階層まで引数としてデータを渡す手間を省き、コードをより見通し良く保つことができます。
なぜ Provider が必要なのか
Flutterでは、シンプルな画面ならばsetStateで状態管理をするのが手っ取り早いかもしれません。
しかし、画面間で共通の変数を扱ったり、画面をまたいでデータを更新したりすると複雑になりがちです。
アプリが複雑になるほど、1つのWidgetでデータ管理するだけでは限界を感じることがあるのではないでしょうか。
Providerは、このようなアプリ全体や複数のWidgetが共通して使うデータをわかりやすい形で管理できます。
結果として、Widget間のデータ渡しが簡素化され、開発時や保守時の混乱を減らす効果が期待できるでしょう。
Provider の導入手順
FlutterのアプリにProviderを組み込むには、pubspec.yamlファイルに依存関係を追加します。
以下はpubspec.yamlの例です。
name: example_provider_app description: A new Flutter project. environment: sdk: ">=2.17.0 <3.0.0" dependencies: flutter: sdk: flutter # Providerパッケージの追加 provider: ^6.0.5 dev_dependencies: flutter_test: sdk: flutter
provider: ^6.0.5
のように書いて依存関係を追加したら、flutter pub get
コマンドで反映させます。
これでコード中からProviderが利用できるようになります。
アプリケーション全体での利用方法
アプリ全体でデータを共有したいときは、main.dartのような最上位のWidgetでProviderをラップする方法がよく使われます。
典型的には、runApp()
の中にMultiProvider
やChangeNotifierProvider
を配置し、その中でアプリ全体を包み込みます。
これにより、ラップしたProviderがアプリ全体から参照できるようになります。
Widget単位での利用方法
画面全体でなく、一部の機能だけProviderを使いたい場面もあるでしょう。
その場合は、Widgetのビルドメソッド内でChangeNotifierProvider
を挟むなどのやり方があります。
必要なときにだけProviderを適用することで、アプリが過度に複雑になるのを防ぎます。
代表的な使い方のコード例
ここでは、ChangeNotifierを利用した簡単なサンプルを見てみましょう。
以下の例では、カウンターの値をProviderで管理し、複数の画面で共有するイメージです。
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; void main() { runApp( ChangeNotifierProvider( create: (_) => CounterModel(), child: MyApp(), ), ); } class CounterModel extends ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } } class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( home: FirstScreen(), ); } } class FirstScreen extends StatelessWidget { Widget build(BuildContext context) { final counter = Provider.of<CounterModel>(context); return Scaffold( appBar: AppBar( title: Text('First Screen'), ), body: Center( child: Text( 'Count: ${counter.count}', style: TextStyle(fontSize: 24), ), ), floatingActionButton: FloatingActionButton( onPressed: counter.increment, child: Icon(Icons.add), ), ); } }
上記のコードでは、CounterModel
というクラスを用意しています。
_count
という変数を持ち、increment
でカウントを増やした後にnotifyListeners()
を呼び出すことで、関連するWidgetに更新を通知しています。
ChangeNotifierProvider
を使うと、Provider.of<CounterModel>(context)
などでモデルを取り出し、自由に操作できます。
Provider を使った具体的な活用シーン
Providerの良さは、単純なカウンター以外にもさまざまな活用シーンがある点です。
以下のようなアプリを作る場合にも、Providerは強い味方になります。
シングルトン管理に活用
アプリ内でユーザー情報を1か所に集約し、あちこちで同じ情報を参照したいケースがあるかもしれません。
たとえば、ログインユーザーの名前やステータス、トークンなどをアプリのどの画面からでも確認したり更新したりしたい場面です。
そうしたデータをProviderで管理すれば、各Widgetで同じUserモデルを読み書きできるため、重複や混乱を防ぐことができるでしょう。
リアルタイム更新に活用
チャットアプリやストリーミング系アプリなど、画面を表示している最中に値が変わり続けることも多いです。
Providerを通じてデータを更新すると、変更を検知して自動でUIが再描画されます。
データを更新するメソッド内でnotifyListeners()
を呼び出す設計であれば、複雑な処理を書かなくてもリアルタイムで画面を刷新できます。
他の状態管理との比較
Flutterには、RiverpodやBlocなど、さまざまな状態管理のアプローチがあります。
Providerは比較的シンプルであるため、初学者には理解しやすいという利点があります。
一方、アプリが大規模化したり、特定のアーキテクチャを厳密に適用したい場面では、ほかの方法を検討してもよいでしょう。
ただし、まずはProviderを押さえておけば、実務でもある程度の規模のアプリを作るうえで十分に対応できるケースが多いと考えられます。
アプリの規模が大きくなると、Providerの数や階層が増え複雑化する可能性があります。 その場合は、Providerを組み合わせる設計や、別の状態管理ライブラリを検討してみても良いでしょう。
まとめ
Flutterでアプリを開発する際、ProviderはWidget間でのデータ共有をわかりやすく実現するための重要な選択肢となります。
アプリ全体を1つのProviderで包み込み、大きな状態を管理してもいいですし、必要な機能ごとにProviderを区切って管理するやり方もあります。
初心者の方でも使いやすい方法なので、まずは小さなプロジェクトで導入し、Providerによる状態管理のメリットを体感してみてはいかがでしょうか。
シンプルな使い方をマスターすると、さまざまなアプリに応用が効くはずです。