1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

状態管理 (Flutter Roadmap State Management)

Posted at

はじめに

Flutterを網羅的に学習するにあたってRoadmapを使って学習を進めることにしました。

この記事では、Flutter初学者やこれからFlutterを学習し始める方に向けて、状態管理についてまとめています。

RoadmapはFlutterだけでなく、他の言語やスキルのロードマップも提供されており、何から学習して良いか分からないと悩んでいる方にとって有用なサイトになっています。
ぜひRoadmapを利用して学習してみてください。

Roadmapとは

簡潔に言えば、Roadmap.shは学習者にとってのガイドブックであり、学習の方向性を提供する学習ロードマップサイトです。

初心者から上級者まで、ステップバイステップでスキルを習得するための情報が提供されています。

学習の進め方が分かりやすく示されているだけでなく、個々の項目に参考資料やリソースへのリンクも提供されているので、学習者は目標を設定し、自分自身のペースで学習を進めることができます。

State Management

FlutterロードマップState Managementでは以下の6つのサイトが紹介されています。興味のある方はぜひお読みください。

状態管理とは

状態管理とは、アプリケーション内でデータの変更を追跡し、それに基づいてUIを更新するプロセスのことです。Flutter の UI は、状態 を build() メソッドで参照しながら構築される設計になっています。そしてその状態の整合性が破綻しないように、「状態をどういうフローでどこに保持するか」、「どのように状態の変更を検知してリビルドするか」ということについて、ルールを決めて扱うということをひとことで 状態管理 と言います。

Flutterにおいて状態はstateと呼ばれ、state(状態)は大きく分けて2種類あります。

一つは Ephemeral state (ローカル状態 / エフェメラル状態)、もう一つは App state (共有状態) です。

Ephemeral state とは、クラス間で共有しない、スコープが閉じたデータ(状態)のことです。例えば ToDoアプリのリストがあります。各ToDoアイテムは、それぞれが削除されるか完了するかなどの状態を持ちます。このToDoアイテムごとの状態は、そのウィジェット内で管理されるのが基本です。ToDoアイテムの削除ボタンを押すと、そのアイテムのローカルな状態が変更され、ウィジェットがリビルドされることで即座に反映されます。基本的に他のクラスから参照されることはないので Ephemeral state と言えます。

一方 App State とは、複数のクラス間で共有されるデータ(状態)のことです。例えばアプリ全体で共有される状態の例として、ユーザーの認証状態があります。ユーザーの認証状態はアプリ全体で共有され、それに基づいてUIや機能が制御されます。認証が必要な画面では、ユーザーがログインしているかどうかに基づいて適切な画面が表示されため App State と言えます。

ChangeNotifier

ChangeNotifierとは、Flutter SDKに含まれている、リスナーに変更通知を提供し、監視可能にさせるためのクラスです。ChangeNotifierを extends しているクラスは、インスタンスの中のメソッドが実行され、状態の変更が発生した際に notifyListeners でUIの更新をトリガーすることができます。

  • notifyListeners(): 登録されたリスナーに変更を通知するメソッドです。状態が変更されたときにこのメソッドが呼び出されます。

サンプルコード

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ChangeNotifierProvider.value(
        value: CounterModel(),
        child: const MyHomePage(),
      ),
    );
  }
}

class CounterModel extends ChangeNotifier {
  int _counter = 0;

  int get counter => _counter;

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

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    final counterModel = context.watch<CounterModel>();

    return Scaffold(
      appBar: AppBar(
        title: const Text('ChangeNotifier Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Counter: ${counterModel.counter}',
              style: const TextStyle(fontSize: 24),
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: () {
                counterModel.increment();
              },
              child: const Text('+1'),
            ),
          ],
        ),
      ),
    );
  }
}
  • CounterModel クラス:

    • ChangeNotifierを継承したモデルクラスです。このクラスで状態を保持し、変更を通知します。
    • _counter プロパティでカウンターの値を格納します。
    • increment メソッドはカウンターを増やし、 notifyListeners メソッドで状態(counter)の変更を通知します。
  • MyHomePage クラス:

    • カウンターの現在の値を表示し、増加ボタンがあるウィジェットです。
    • context.watch<CounterModel>()CounterModel インスタンスを取得し、その変更を購読します。
  • ChangeNotifierProvider:

    • ChangeNotifierProviderCounterModel クラスを指定し、子ウィジェットでその変更を監視できるようにします。

ValueNotifier

ValueNotifier とは、 ChangeNotifier を簡略化した状態管理クラスです。単一の値の変更を通知し、それに応じてリスナーが処理を実行できるようになります。 ChangeNotifier とは異なり、 ValueNotifiernotifyListeners メソッドを持たず、代わりに value プロパティを通じて現在の値にアクセスすることができます。

ValueNotifierは ChangeNotifier を継承(extends)し ValueListenable を実装(implements)したクラスです。 ChangeNotfier を継承しているので、 ChangeNotifier と同じように使うことができますが、状態変数は一つしか持ちません。

メリット

  • シンプルな値の管理: 状態変数が一つに強制されるので、状態管理クラスがシンプルに保たれます。そのため、単一の値の変更を管理するのに適しています。

  • 簡潔な記述: ValueNotifier は、 ChangeNotifier よりもメソッドが少なく、直感的に使用することができます。 ChangeNotifier には notifyListeners メソッドがあり、手動で呼び出す必要がありますが、 ValueNotifier は直接、値を更新することで変更を通知するため、notifyListeners の呼び忘れによるバグを防ぐことができます。

デメリット

  • 複雑な状態管理: 複雑な状態管理が必要な場合、 ValueNotifier は単一の値しかサポートしていないため、十分な柔軟性がありません。

  • 複数のリスナー: ValueNotifier は複数のリスナーをサポートしていますが、複数のリスナーが同じイベントに対して異なる処理を実行する必要がある場合、 ChangeNotifier の方が適しています。

  • Providerとの統合: ChangeNotifierProvider パッケージとの統合が容易で、多くの状態管理ライブラリで使用されている、一方で、 ValueNotifierProvider との統合が限定的です。

ValueListenableBuilder

ValueListenableBuilder とは、 ValueListenableオブジェクト に登録された値を監視し、その値の変更に応じて、ウィジェットツリーを再構築する、Flutterで提供されているウィジェットのことです。非同期処理もサポートしており、 FutureStream といった非同期イベントの監視にも利用できます。

主なプロパティ

  • valueListenable: ValueListenableのオブジェクトです。これが変更されると、 builder 関数が呼び出されます。
  • builder: ウィジェットを構築するコールバック関数です。第二引数には valueListenable に登録されている現在の値が渡され、これに基づいてウィジェットが再構築されます。
  • child(オプション): オプションの child ウィジェットです。このプロパティは静的な部分で、再構築される必要がない場合に使用されます。

サンプルコード

import 'package:flutter/material.dart';

class CounterModel extends ValueNotifier<int> {
  CounterModel(int value) : super(value);

  void increment() {
    value += 1;
  }
}

class MyHomePage extends StatelessWidget {
  final CounterModel counterModel;

  MyHomePage({Key? key, required this.counterModel}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ValueNotifier Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ValueListenableBuilder<int>(
              valueListenable: counterModel,
              builder: (context, value, child) {
                return Text(
                  'Counter: $value',
                  style: const TextStyle(fontSize: 24),
                );
              },
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: () {
                counterModel.increment();
              },
              child: const Text('+1'),
            ),
          ],
        ),
      ),
    );
  }
}

void main() {
  runApp(
    MaterialApp(
      home: MyHomePage(
        counterModel: CounterModel(0),
      ),
    ),
  );
}
  • CounterModel クラス:

    • ValueNotifier<int> を継承しているクラスです。これは int 型の値を保持する ValueNotifier として機能します。
    • increment メソッドで、現在の値(value)に1を加えています。
  • MyHomePage クラス:

    • counterModel プロパティで、 CounterModel のインスタンスを受け取ります。
    • ValueListenableBuilder を使用して、 counterModel の値の変更を検知し、UIを更新しています。ボタンが押されたときに counterModel.increment() を呼び出して値を増加させています。

まとめ

  • 状態管理 (State Management):
    アプリケーション内でデータの変更を追跡し、それに基づいてUIを更新するプロセスのことです。Ephemeral state(ローカル状態)とApp state(共有状態)があり、UI構築において状態の整合性を保つための管理が重要になります。

  • ChangeNotifier:
    Flutterに含まれる状態管理クラスで、リスナーに変更通知を提供し、UIの更新をトリガーするクラスになります。notifyListeners メソッドを使用して変更を通知し、値を更新します。

  • ValueNotifier:
    ChangeNotifier を簡略化した状態管理クラスで、単一の値の変更を通知します。シンプルで簡潔な記述が可能でValueListenableBuilder を使用して値の変更を検知し、UIを再構築します。

状態管理はアプリケーション開発において重要な概念であり、適切な方法を選択することでアプリケーションのパフォーマンスやメンテナンス性を向上させます。 ChangeNotifierValueNotifier はシンプルで小規模なアプリケーションに適しているため、必要に応じてより高度な状態管理パターンやライブラリを活用することが重要になってきます。

参考資料

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?