Flutter開発入門49 Providerパターンを使ったシンプルな状態管理

Flutter

はじめに

Flutterでアプリケーションを開発する際、状態管理は避けて通れない課題です。特に規模が大きくなるアプリでは、効率的に状態を管理し、UIとビジネスロジックを分離する設計が重要になります。そこで登場するのがProviderパターンです。FlutterのProviderパッケージは、公式が推奨する状態管理の方法で、シンプルでありながら強力です。

この記事では、Flutterの公式ドキュメントに基づき、Providerパターンによるシンプルな状態管理について解説します。初めてFlutterで状態管理を学ぶ方にも理解しやすいように、基本的な概念から実際のコード例まで紹介します。

Providerパターンとは

Providerパターンは、Flutterでの状態管理を簡潔かつ効率的に行うための設計パターンです。Providerは依存性注入の仕組みを提供し、データの共有とUIの更新を容易にします。特に、状態が変わるたびにUIをリビルドする必要がある場合に便利です。

Providerパターンの主な特徴

  • 簡単な実装:シンプルなAPIで、状態管理を導入しやすい。
  • 依存関係の注入:データを必要な場所に簡単に渡すことができる。
  • 自動的なUIの更新:状態が変わった時点で、必要なウィジェットのみが再レンダリングされる。
  • グローバルに状態を共有:状態をどこからでもアクセス可能にし、コードの再利用性が向上。

Providerパターンの基本的な使い方

1. セットアップ

まず、pubspec.yamlファイルにproviderパッケージを追加します。

dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.0

その後、依存関係をインストールします。

flutter pub get

2. Providerの構造

Providerパターンでは、状態を管理するクラスと、そのクラスを使ってUIを更新する流れが基本です。大まかな構造は以下の通りです。

  • モデルクラス:状態を保持し、更新するメソッドを持つクラス。
  • ChangeNotifier:状態の変更をリスナーに通知するためのクラス。モデルクラスはChangeNotifierを継承します。
  • Consumerウィジェット:状態を監視し、UIを更新するために使われるウィジェット。

シンプルなカウンターアプリの例

1. モデルクラスの作成

まずは、状態を管理するためのモデルクラスを作成します。このクラスでは、カウンターの値を保持し、値を増加させるメソッドを定義します。

import 'package:flutter/foundation.dart';

class CounterModel with ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

解説

  • ChangeNotifierwith ChangeNotifierを使うことで、リスナーに状態の変更を通知できます。
  • notifyListeners():状態が変更されたことを通知し、UIが自動的に更新される仕組みを提供します。

2. Providerを使ったウィジェットの構築

次に、Providerを使ってアプリケーション全体でこのモデルクラスを提供します。Providerで状態をラップし、Consumerウィジェットを使ってUIを更新します。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter_model.dart'; // モデルクラスをインポート

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => 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('Counter App with Provider')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('You have pushed the button this many times:'),
            Consumer<CounterModel>(
              builder: (context, counter, child) {
                return Text(
                  '${counter.count}',
                  style: Theme.of(context).textTheme.bodySmall,
                );
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Provider.of<CounterModel>(context, listen: false).increment();
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

解説

  • ChangeNotifierProviderChangeNotifierを使って、状態をアプリ全体に提供するプロバイダです。createでインスタンスを生成します。
  • ConsumerConsumerウィジェットは、プロバイダの状態を監視し、状態が変わるたびにUIを更新します。
  • Provider.ofProvider.of<CounterModel>(context)で、プロバイダにアクセスし、状態を操作します。listen: falseにすることで、状態が変わっても再ビルドされないようにします。

複雑な状態管理への拡張

Providerパターンは、シンプルなアプリから複雑なアプリまでスケーラブルに対応できます。例えば、以下のような機能を追加することが可能です。

1. 複数のProviderを使用する

MultiProviderを使うことで、複数の状態を同時に管理できます。たとえば、カウンターの状態とユーザーの認証状態をそれぞれ管理する場合に便利です。

MultiProvider(
  providers: [
    ChangeNotifierProvider(create: (context) => CounterModel()),
    ChangeNotifierProvider(create: (context) => AuthModel()),
  ],
  child: MyApp(),
)

2. 非同期処理との統合

Providerは非同期データにも対応可能です。例えば、APIリクエストを実行して、取得したデータをUIに反映することができます。FutureProviderStreamProviderを使えば、非同期データを簡単に扱えます。

Providerパターンのメリットとベストプラクティス

メリット

  1. シンプルなAPIProviderの使い方は非常にシンプルで、導入が簡単。
  2. テストがしやすい:ビジネスロジックとUIが分離されているため、テストが容易。
  3. パフォーマンスが高い:状態が変更されたときに必要な部分だけをリビルドするため、パフォーマンスに優れています。

ベストプラクティス

  • 状態のロジックを分離する:ビジネスロジックはモデルクラスにまとめ、UIはUIに専念させる。
  • Providerの適切な配置:アプリ全体で共有する必要がある状態は、MaterialAppの近くに配置し、ローカルな状態はより下層のウィジェットに配置する。

まとめ

FlutterのProviderパターンは、シンプルかつ強力な状態管理方法を提供します。ChangeNotifierを使って状態を簡単に管理し、ConsumerProvider.ofでUIに反映することで、効率的な状態管理が可能になります。また、複数のプロバイダや非同期処理も簡単に扱えるため、スケーラブルなアプリケーション開発が可能です。

コメント