web-dev-qa-db-ja.com

Provider <SomeType> .of(context、listen:false)と一緒に使用すると、listen:falseがどのように機能するかを理解する

ProviderパッケージがFlutterでどのように機能するかを理解するために作業していますが、listen:falseの機能について混乱しています。

新しいFlutterプロジェクトの通常のCounterサンプルを使用して、いくつかの基本的なコードを書きました。それぞれプロバイダーを使用して、3種類のステートレスウィジェットを作成しました。

  1. Provider.of(コンテキスト)
  2. 消費者
  3. Provider.of(コンテキスト、リッスン:false)

3番目の例は、プロバイダーオブジェクトにアクセスし、再構築せずにそのオブジェクトのメソッドを呼び出す方法を示すことです。

アプリケーションを実行すると、すべてのウィジェットの数が変化します-最初の2つだけが変化すると予想しています。

これは簡単な例です-何がいけないのですか?

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

void main() => runApp(MyApp());

class Counter with ChangeNotifier {
  int _count = 0;
  int get count => _count;

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(builder: (_) => Counter()),
      ],
      child: MaterialApp(
        title: 'Provider Demo',
        theme: ThemeData(
          primarySwatch: Colors.amber,
        ),
        home: MyHomePage(title: 'Provider Demo Home Page'),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  Widget build(BuildContext context) {
    Counter counter = Provider.of<Counter>(context);
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ExampleProviderWidget(),
            ExampleConsumerWidget(),
            ExampleNoListenWidget()
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counter.increment(),
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

class ExampleProviderWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Counter counter = Provider.of<Counter>(context);

    return Container(
      color: Colors.green,
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Provider.of<Counter>(context):',
            ),
            Text(
              '${counter.count}',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
    );
  }
}

class ExampleConsumerWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<Counter>(
      builder: (context, counter, _) {
        return Container(
          color: Colors.blue,
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'Consumer<Counter>(context):',
                ),
                Text(
                  '${counter.count}',
                  style: Theme.of(context).textTheme.display1,
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}

class ExampleNoListenWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Counter counter = Provider.of<Counter>(context, listen: false);

    return Container(
      color: Colors.red,
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Provider.of<Counter>(context, listen: false):',
            ),
            Text(
              '${counter.count}',
              style: Theme.of(context).textTheme.display1,
            ),
            RaisedButton(
              child: Text("Increment"),
              onPressed: () => counter.increment(),
            )
          ],
        ),
      ),
    );
  }
}

4
Joe Nalewabau

レミが提案したのは、実用的なアプローチ(ハック)です。しかし、この場合のより良い方法は、呼び出しCounter counter = Provider.of(context);を削除することだと思います。 MyHomePageClassから。その呼び出しはCounterオブジェクトのスコープを汚染しています。 flutter.ioで提案されているように、 コンシューマウィジェットをツリーのできるだけ奥に配置することをお勧めします 。 ExampleProviderWidget()、ExampleConsumerWidget()、ExampleNoListenWidget()で行ったように。したがって、floatingActionButtonを別個のウィジェットクラスにして、独自のProvider.of(context)を作成します。また、MyHomePageClassはProvider.ofを呼び出す必要はありません。

0
mykey