🤖

【Flutter】 Provider

2021/08/21に公開

Provider

  • プロバイダーウィジェットタイプの中で最も基本
  • ウィジェットツリーの任意の場所に値を提供
  • 値の変更キャッチして再描画はしない
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return Provider<MyModel>(
      create: (context) => MyModel(),
      child: MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: Text('Flutter Demo')
          ),

          backgroundColor: Colors.white,

          body: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Container(
                padding: const EdgeInsets.all(20),
                color: Colors.green[200],
                child: Consumer<MyModel>(
                  builder: (context, myModel, child) {
                    return RaisedButton(
                      child: Text('Do something'),
                      onPressed: () {
                        myModel.doSomething();
                      },
                    );
                  }
                )
              ),
              Container(
                padding: const EdgeInsets.all(35),
                color: Colors.blue[200],
                child: Consumer<MyModel>(
                  builder: (context, myModel, child) {
                    return Text(myModel.someValue);
                  },
                )
              )
            ]
          )
        )
      )
    );
  }
}

class MyModel {
  String someValue = 'hello';

  void doSomething() {
    someValue = 'Goodbye';
    print(someValue);
  }
}

ChangeNotifierProvider

  • 値の変更をリッスンする。ウィジェット再構築
  • モデルクラスではChangeNotifier ミックスインする必要あり
  • notifyListeners()を呼び出すとChangeNotifierProviderが通知され、Consumerがウィジェットを再描画してくれる
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<MyModel>(
      create: (context) => MyModel(),
      child: MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: Text('Flutter Demo')
          ),

          backgroundColor: Colors.white,
          body: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Container(
                padding: const EdgeInsets.all(20),
                color: Colors.green[200],
                child: Consumer<MyModel>(
                  builder: (context, myModel, child) {
                    return RaisedButton(
                      child: Text('Do something'),
                      onPressed: () {
                        myModel.doSomething();
                      },
                    );
                  }
                )

              ),
              Container(
                padding: const EdgeInsets.all(35),
                color: Colors.blue[200],
                child: Consumer<MyModel>(
                  builder: (context, myModel, child) {
                    return Text(myModel.someValue);
                  },
                )
              )
            ]
          )
        )
      )
    );
  }
}

class MyModel with ChangeNotifier {
  String someValue = 'hello';

  void doSomething() {
    if (someValue == 'hello') {
      someValue = 'Goodbye';
    } else {
      someValue = 'hello';
    }
    print(someValue);
    notifyListeners();
  }
}

FutureProvider

  • 指定した Future のタスクが完了するのをリッスンすし、ウィジェットを再描画(再構築)
  • 主に、HTTPリクエストやローカルファイルの読み込みなどで利用する
  • AsyncValue という Riverpod 独自のオブジェクトで返される
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return FutureProvider<MyModel>(
      initialData: MyModel(value: 'default value'),
      create: (context) => someAsyncFunctionToGetMyModel(),
      child: MaterialApp(
        home: Scaffold(
          title: Text('Flutter Demo')
        ),
        
        backgroundColor: Colors.white,
        
        body: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              padding: const EdgeInsets.all(20),
              color: Colors.green[200],
              child: Consumer<MyModel>(
                builder: (context, myModel, child) {
                  return RaisedButton(
                    child: Text('Do something'),
                    onPressed: () {
                      myModel.doSomething();
                    },
                  );
                }
              )
            ),
            Container(
              padding: const EdgeInsets.all(35),
              color: Colors.blue[200],
              child: Consumer<MyModel>(
                builder: (context, myModel, child) {
                  return Text(myModel.someValue);
                },
              )
            )
          ]
        )
      )
    )
  }
}

Future<MyModel> someAsyncFunctionToGetMyModel() async {
  await Future.delayed(Duration(seconds: 5));
  return MyModel(value: 'new data');
}

class MyModel {
  String someValue = 'hello';

  MyModel({ value }) {
    someValue = value;
  }

  Future<void> doSomething() async {
    await Future.delayed(Duration(seconds: 2));
    
    // ここが変更されてもウジェットの値は変わらない(際描画されるない)」
    someValue = 'Goodbye';
    print(someValue);
  }
}

Discussion