I am using provider in my app, but I faced with unnecessary building.
Example
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.increament(),
);
}
}
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.decreament(),
);
}
}
Now if I click on MyIncreaseButton
widget, to inscrease the value, the MyDecreaseButton
widget builds too, even when I dont click on it.
And vice versa, if I click on MyDecreaseButton
widget, to descrease the value, the MyIncreaseButton
widget builds too, even when I dont click on it.
My Expectation is:
When clicking MyIncreaseButton
widget, MyDecreaseButton
widget should not build.
There are multiple solutions:
context.read
or pass listen: false
to 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(),
);
},
);
}