我一直在理解Provider程序包如何与Flutter一起工作,但对listen:false的工作方式感到困惑。
我使用来自新Flutter项目的常规Counter示例编写了一些基本代码。我使用提供程序创建了三种类型的无状态小部件:
第三个示例显示了如何在不重建提供程序对象的情况下访问该提供程序对象并对其调用方法。
当我运行应用程序时,所有小部件计数都在变化-我只希望它在前两个中有所变化。
这是一个简单的示例-我在做什么错了?
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(),
)
],
),
),
);
}
}
答案 0 :(得分:0)
这是因为,虽然没有重建且用Provider.of
调用的listen:false
的小部件想要重建,但其父级却强制重建。
在您的示例中,当Counter
发生更改时,MyHomePage
重建并重新创建指定了listen:false
的小部件,这又迫使其也重建。
MyHomePage
在这里也应指定listen: false
。
答案 1 :(得分:0)
Remi建议的是一种可行的方法(黑客)。 但我相信在这种情况下,更好的方法是删除通话 Counter counter = Provider.of(context);从MyHomePageClass。该调用污染了Counter对象的范围。 如flutter.io所建议的,It is best practice to put your Consumer widgets as deep in the tree as possible。就像在ExampleProviderWidget(),ExampleConsumerWidget(),ExampleNoListenWidget()中一样。因此,将floatActionButton设为一个单独的小部件类,并拥有自己的Provider.of(context)。 而且您的MyHomePageClass不必调用Provider.of。
答案 2 :(得分:0)
对我有用
I/flutter (12384): MyApp build
I/flutter (12384): MyHomePage build
I/flutter (12384): ExampleProviderWidget build
I/flutter (12384): ExampleConsumerWidget build
I/flutter (12384): ExampleNoListenWidget build
Reloaded 1 of 524 libraries in 792ms.
I/flutter (12384): ExampleProviderWidget build
I/flutter (12384): ExampleProviderWidget build
I/flutter (12384): ExampleProviderWidget build
I/flutter (12384): ExampleProviderWidget build
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) {
print('MyApp build');
return 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;
Counter _counter = Counter();
@override
Widget build(BuildContext context) {
print('MyHomePage build');
return ChangeNotifierProvider.value(
value: _counter,
child: 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) {
print('ExampleProviderWidget build');
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) {
print('ExampleConsumerWidget build');
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) {
print('ExampleNoListenWidget build');
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(),
)
],
),
),
);
}
}
答案 3 :(得分:0)
根据您编写的代码,您在 onPressed 方法中使用的 increment 方法将不起作用,如果您实现了 listen: false.