ChangeNotifierProvider 中的 Consumer / Provider.of 差异

Difference Consumer / Provider.of in ChangeNotifierProvider

我不太明白 Provider.of() 和 Consumer 之间的区别。 我读过 消费者就像 Provider.of with listen: true.

然而,在下面的示例中,当我使用 Consumer 时我没有收到错误,但我在使用 Provider.of 时收到错误。我被迫使用 listen: false。下面的示例是实现了 ChangeNotifierProvider 的默认 flutter 应用程序。

我将只更改 main.dart 中的 floatingActionButton 中的代码,以查看 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 的 floatingActionButton。正在运行

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 的 floatingActionButton 代码,听:正确,不起作用

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

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

使用 Provider.of 的 floatingActionButton 代码,监听:false,有效

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

我不明白。我放了 listen: false,但它仍在监听和重建小部件

感谢您的帮助

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),
),