Menu
CoddyTech

Provider:Modelを共有する

CoddyのFlutterジャーニー「状態管理」セクションの一部。レッスン 9/27。

ウィジェット同士が近くにある場合は、状態を上位に持ち上げる方法が有効です。アプリ全体のあちこち、たとえば2つの画面、トップバー、リストの奥深くで値が必要になると、その間にあるすべてのウィジェットを通して値を渡すことになります。Providerを使えば、その手間を省けます。これはパッケージです。import 'package:provider/provider.dart';でインポートするコードの集まりです。

これには3つの要素があります。まずモデルです。データを保持し、extends ChangeNotifierを持つクラスです。そのメソッドでデータを変更し、その後notifyListeners()を呼び出します。

class CupCounter extends ChangeNotifier {
  int _cups = 0;
  int get cups => _cups;

  void addCup() {
    _cups++;
    notifyListeners();
  }
}

次に、ツリーの上位に置かれたChangeNotifierProviderがモデルを一度作成し、その下にあるすべてのウィジェットに渡します。

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

最後に、その下にある任意のウィジェットからモデルを取得します。表示するにはcontext.watch<CupCounter>()を、メソッドを呼び出すにはcontext.read<CupCounter>()を使います。下にあるタイトルとボタンは同じカウンターを取得し、どちらにも何かを渡す必要はありません。

challenge icon

チャレンジ

中級

アプリを開くとエラーが表示されます。タイトルが CupCounter を要求しているのに、それより上の部分で何も提供していないためです。

  • main で、CupCounter を作成する ChangeNotifierProvider で MyApp をラップします。

自分で試してみよう

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

class CupCounter extends ChangeNotifier {
  int _cups = 0;

  int get cups => _cups;

  void addCup() {
    _cups++;
    notifyListeners();
  }
}

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const CupsTitle()),
      body: const Center(child: AddCupButton()),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    final counter = context.watch<CupCounter>();
    return Text('Cups: ${counter.cups}');
  }
}

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

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {
        context.read<CupCounter>().addCup();
      },
      child: const Text('Another cup'),
    );
  }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

状態管理のすべてのレッスン

自分で練習してみよう: Flutterオンラインコンパイラ