☺️

ChangeNotifierProviderにてログイン状態を別ウィジェットでも使用できるようにする実装方針

2024/08/18に公開

コードの可読性向上のためにFirebaseのログイン状態管理を別クラスに切り出す実装をした。
その際にChangeNotifierProviderを使用したので、最小の実装を紹介する。
(反響があればfirebaseのログイン状態管理をまとめる)

やりたいこと

  • ログイン状態を別クラスのインスタンスで管理して、別ウィジェットからアクセスできるようにしたい
  • 状態管理をウィジェットから独立させて、コードをわかりやすくしたい

カウンターアプリでのChangeNotifierProvider実装例

以下の3ステップ

  1. 状態管理したい対象を準備
  2. 状態管理を使用したいウィジェットを定義
  3. 状態管理された対象を利用する

状態管理したい対象を準備

Counter クラスは ChangeNotifier を継承しており、状態を管理するためのメソッド (increment) と状態の変更を通知するための notifyListeners メソッドを提供している。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class Counter with ChangeNotifier {
  int _count = 0;

  int get count => _count;

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

状態管理を使用したいウィジェットを定義

main 関数で ChangeNotifierProvider を使って、アプリ全体に Counter クラスのインスタンスを提供しています。
Counter クラスのインスタンスの利用範囲は実装の煩雑さを防ぐために大きすぎない方がよろしい。

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => Counter(),
      child: MyApp(),
    ),
  );
}

状態管理された対象を利用する

context.watch<Counter>() を使って、Counter クラスの count の値を取得し、それに応じてUIを更新します。
watch メソッドは、プロバイダが提供する値を監視し、値が変わるとウィジェットを再ビルドする。

context.read<Counter>() を使って、Counter クラスのメソッドを呼び出し、状態を変更する。
read メソッドは、状態の変更をトリガーするのに使用され、UIの再ビルドしない。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Counter App')),
        body: Center(
          child: Text(
            '${context.watch<Counter>().count}',
            style: TextStyle(fontSize: 48),
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => context.read<Counter>().increment(),
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

Discussion