ChangeNotifierProvider中的差异使用者/Provider.of

时间:2020-10-12 13:18:59

标签: flutter flutter-provider

我不太了解Provider.of()和Consumer之间的区别。 我已经读过here,消费者就像Provider.of一样,具有listen:true。

但是,在下面的示例中,使用Consumer时没有出现错误,但是使用Provider.of时出现了错误。我被迫使用listen:false。以下示例是已实现ChangeNotifierProvider的默认Flutter应用。

我将只更改main.dart中的floatActionButton中的代码,以查看Consumer,Provider.of listen:true和Provider.of listen:false

之间的差异

counter.dart代码

import 'package:flutter/material.dart';

class Counter extends ChangeNotifier {
  int value = 0;

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

  void decrement() {
    value--;
    notifyListeners();
  }
}

main.dart的完整代码,带有使用Consumer的floatActionButton。它正在工作

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

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: ChangeNotifierProvider<Counter>(
        create: (context) => Counter(),
        child: MyHomePage(title: 'Flutter Demo Home Page'),
      ),
    );
  }
}

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

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Consumer<Counter>(builder: (context, counter, child) {
              return Text(
                counter.value.toString(),
                style: Theme.of(context).textTheme.headline4,
              );
            }),
          ],
        ),
      ),
      floatingActionButton:
          Consumer<Counter>(builder: (context, counter, child) {
        return FloatingActionButton(
          onPressed: () {
            counter.increment();
          },
          tooltip: 'Increment',
          child: Icon(Icons.add),
        );
      }),
    );
  }
}

使用Provider.of的floatActionButton的代码,请听:true,不起作用

floatingActionButton: FloatingActionButton(
        onPressed: () {
          Provider.of<Counter>(context, listen: true).increment();
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),

错误:试图从小部件树的外部监听提供程序公开的值...

使用Provider.of的floatActionButton的代码,侦听:false,有效

floatingActionButton: FloatingActionButton(
    onPressed: () {
      Provider.of<Counter>(context, listen: false).increment();
    },
    tooltip: 'Increment',
    child: Icon(Icons.add),
  ),

我不明白。我把listen:设置为false,但它仍在监听并重建小部件

感谢您的帮助

1 个答案:

答案 0 :(得分:2)

listen:true 需要放入构建小部件树中。它的目的是在调用时重建整个小部件(notifyListener)。

@override
  Widget build(BuildContext context) {
    Counter counter = Provider.of<Counter>(context, listen: true);
...
    counter.increment(); // Will rebuild entire widget.
...

Consumer 是一个在其中调用 listen:true 的小部件,但只会重建它的子小部件。

Consumer<Counter>(builder: (_, counter, __) {
  return Column(
    children:[
      TextButton(
        onPressed: () => counter.increment(), // Will only rebuild this Column
        child: Icon(Icons.add),),
      Text(counter.value.toString());
}),

listen:false 将访问 Provider,如果调用,则无需重建小部件。

TextButton(
  onPressed: () { 
    Counter counter = Provider.of<Counter>(context, listen: false);
    counter.increment(); 
    // Will change Provider value, but won't rebuild. It will make widget that has 
    // Consumer as parent to rebuild (or with listen:true to rebuild). 
  }
  child: Icon(Icons.add),
),