在 flutter 中使用提供者时如何避免不必要的重建?
How to avoid unnecessary rebuilds while using provider in flutter?
我正在我的应用程序中使用 provider,但我遇到了不必要的构建。
例子
class AllWidget extends StatelessWidget{
@override
Widget build(BuildContext context){
print('state build called');
return ChangeNotifierProvider(
builder: (_) => MyCounter(),
child: Column(children: <Widget>[
MyCounterText(),
MyIncreaseButton(),
MyDecreaseButton(),
],
),
);
}
}
class MyCounterText extends StatelessWidget{
@override
Widget build(BuildContext context) {
final myCounter = Provider.of<MyCounter>(context, listen: false);
print('MyCounterText');
return Text(myCounter.num.toString());
}
}
class MyIncreaseButton extends StatelessWidget{
@override
Widget build(BuildContext context) {
final myCounter = Provider.of<MyCounter>(context, listen: false);
print('MyIncreaseButton');
return RaisedButton(
child: Text('Increase +'),
onPressed: ()=> myCounter.increment(),
);
}
}
class MyDecreaseButton extends StatelessWidget{
@override
Widget build(BuildContext context) {
final myCounter = Provider.of<MyCounter>(context, listen: false);
print('MyDecreaseButton');
return RaisedButton(
child: Text('Decrease -'),
onPressed: ()=> myCounter.decrement(),
);
}
}
现在,如果我点击 MyIncreaseButton
小部件,为了增加价值,MyDecreaseButton
小部件也会构建,即使我没有点击它。
反之亦然,如果我点击 MyDecreaseButton
小部件,为了减小值,MyIncreaseButton
小部件也会构建,即使我没有点击它也是如此。
我的期望是:
单击 MyIncreaseButton
小部件时,MyDecreaseButton
小部件不应构建。
有多种解决方案:
- 使用
context.read
或将 listen: false
传递给 Provider.of
:
RaisedButton(
onPressed: () {
context.read<MyModel>().increment();
// alternatively, do:
Provider.of<MyModel>(context, listen: false).increment();
},
child: Child(),
);
- 使用
context.select
:
Widget build(context) {
final increment = context.select((MyModel m) => m.increment);
return RaisedButton(
onPressed: increment,
child: Child(),
);
}
- 使用
Selector
:
Widget build(context) {
return Selector<MyModel, VoidCallback>(
selector: (_, model) => model.increment,
builder: (_, increment) {
return RaisedButton(
onPressed: increment,
child: Child(),
);
},
);
}
选择器正是您所需要的。使用选择器,您可以过滤更新。
例如要仅在名称更改时更新,您可以这样做
Selector<AppStore, String>(
selector: (_, store) => store.name,
builder: (_, name, __) {
return Text(name);
},
);
我只是通过如下编辑代码来避免不必要的渲染:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter/foundation.dart';
class MyCounter with ChangeNotifier {
int _num = 0;
int get num => _num;
set num(int n) {
_num = n;
notifyListeners();
}
void increaent() {
_num = _num + 1;
notifyListeners();
}
void decrement() {
_num = _num - 1;
notifyListeners();
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('root build called');
return ChangeNotifierProvider(
builder: (context) => MyCounter(),
child: MaterialApp(
title: 'MyAppJan',
home: Scaffold(
appBar: AppBar(title: Text('Home')),
body: AllWidget(),
),
theme: ThemeData(primarySwatch: Colors.orange),
));
}
}
class AllWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('state build called');
return Center(
child: Column(
children: <Widget>[
MyCounterText(),
SizedBox(height: 10),
MyIncreaseButton(),
SizedBox(height: 10),
MyDecreaseButton(),
],
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
),
);
}
}
class MyCounterText extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('MyCounterText');
return Consumer<MyCounter>(
builder: (context, myCounter, _) {
return Text(myCounter.num.toString());
},
);
}
}
class MyIncreaseButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final _items = Provider.of<MyCounter>(context,listen: false);
print('MyIncreaseButton');
return RaisedButton(
child: Text('Increase ++'),
onPressed: () => _items.increment(),
);
}
}
class MyDecreaseButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final _items = Provider.of<MyCounter>(context,listen: false);
print('MyDecreaseButton');
return RaisedButton(
child: Text('Decrease --'),
onPressed: () => _items.decrement(),
);
}
}
我正在我的应用程序中使用 provider,但我遇到了不必要的构建。
例子
class AllWidget extends StatelessWidget{
@override
Widget build(BuildContext context){
print('state build called');
return ChangeNotifierProvider(
builder: (_) => MyCounter(),
child: Column(children: <Widget>[
MyCounterText(),
MyIncreaseButton(),
MyDecreaseButton(),
],
),
);
}
}
class MyCounterText extends StatelessWidget{
@override
Widget build(BuildContext context) {
final myCounter = Provider.of<MyCounter>(context, listen: false);
print('MyCounterText');
return Text(myCounter.num.toString());
}
}
class MyIncreaseButton extends StatelessWidget{
@override
Widget build(BuildContext context) {
final myCounter = Provider.of<MyCounter>(context, listen: false);
print('MyIncreaseButton');
return RaisedButton(
child: Text('Increase +'),
onPressed: ()=> myCounter.increment(),
);
}
}
class MyDecreaseButton extends StatelessWidget{
@override
Widget build(BuildContext context) {
final myCounter = Provider.of<MyCounter>(context, listen: false);
print('MyDecreaseButton');
return RaisedButton(
child: Text('Decrease -'),
onPressed: ()=> myCounter.decrement(),
);
}
}
现在,如果我点击 MyIncreaseButton
小部件,为了增加价值,MyDecreaseButton
小部件也会构建,即使我没有点击它。
反之亦然,如果我点击 MyDecreaseButton
小部件,为了减小值,MyIncreaseButton
小部件也会构建,即使我没有点击它也是如此。
我的期望是:
单击 MyIncreaseButton
小部件时,MyDecreaseButton
小部件不应构建。
有多种解决方案:
- 使用
context.read
或将listen: false
传递给Provider.of
:
RaisedButton(
onPressed: () {
context.read<MyModel>().increment();
// alternatively, do:
Provider.of<MyModel>(context, listen: false).increment();
},
child: Child(),
);
- 使用
context.select
:
Widget build(context) {
final increment = context.select((MyModel m) => m.increment);
return RaisedButton(
onPressed: increment,
child: Child(),
);
}
- 使用
Selector
:
Widget build(context) {
return Selector<MyModel, VoidCallback>(
selector: (_, model) => model.increment,
builder: (_, increment) {
return RaisedButton(
onPressed: increment,
child: Child(),
);
},
);
}
选择器正是您所需要的。使用选择器,您可以过滤更新。 例如要仅在名称更改时更新,您可以这样做
Selector<AppStore, String>(
selector: (_, store) => store.name,
builder: (_, name, __) {
return Text(name);
},
);
我只是通过如下编辑代码来避免不必要的渲染:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter/foundation.dart';
class MyCounter with ChangeNotifier {
int _num = 0;
int get num => _num;
set num(int n) {
_num = n;
notifyListeners();
}
void increaent() {
_num = _num + 1;
notifyListeners();
}
void decrement() {
_num = _num - 1;
notifyListeners();
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('root build called');
return ChangeNotifierProvider(
builder: (context) => MyCounter(),
child: MaterialApp(
title: 'MyAppJan',
home: Scaffold(
appBar: AppBar(title: Text('Home')),
body: AllWidget(),
),
theme: ThemeData(primarySwatch: Colors.orange),
));
}
}
class AllWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('state build called');
return Center(
child: Column(
children: <Widget>[
MyCounterText(),
SizedBox(height: 10),
MyIncreaseButton(),
SizedBox(height: 10),
MyDecreaseButton(),
],
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
),
);
}
}
class MyCounterText extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('MyCounterText');
return Consumer<MyCounter>(
builder: (context, myCounter, _) {
return Text(myCounter.num.toString());
},
);
}
}
class MyIncreaseButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final _items = Provider.of<MyCounter>(context,listen: false);
print('MyIncreaseButton');
return RaisedButton(
child: Text('Increase ++'),
onPressed: () => _items.increment(),
);
}
}
class MyDecreaseButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final _items = Provider.of<MyCounter>(context,listen: false);
print('MyDecreaseButton');
return RaisedButton(
child: Text('Decrease --'),
onPressed: () => _items.decrement(),
);
}
}