Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid unnecessary rebuilds while using provider in flutter?

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.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(),
    );

  }
}

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.

like image 431
Muhammad Avatar asked Jun 08 '19 09:06

Muhammad


People also ask

How do I stop rebuilding in Flutter?

ShouldRebuild. A widget can prevent Child Widget unnecessary rebuilds. You can filter whether you need rebuild based on whether the property values received by the old Child Widget and the new Child Widget are equal.

How do you deal with unwanted widget build in Flutter?

One of the easiest ways to avoid unwanted reBuilds that are caused usually by calling setState() in order to update only a specific Widget and not refreshing the whole page, is to cut that part of your code and wrap it as an independent Widget in another Stateful class.

How do you consume providers in Flutter?

Example Using Provider So, first to get the String value created in the main. dart , all we have to do is call Provider. of<String>(context) , the of() method here will obtain the nearest Provider up its widget tree and returns its value.

Why does my widget rebuild when I use keyboard?

the only reason why your widgets got rebuilds after keyboard pop up. is that one or more of your widgets size depends on MediaQuery. you can try to ge your screen size from LayoutBuilder as an alternative for MediaQuery.


2 Answers

There are multiple solutions:

  • use 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(),
);
  • use context.select:
Widget build(context) {
  final increment = context.select((MyModel m) => m.increment);

  return RaisedButton(
    onPressed: increment,
    child: Child(),
  ); 
}
  • use Selector:
Widget build(context) {
  return Selector<MyModel, VoidCallback>(
    selector: (_, model) => model.increment,
    builder: (_, increment) {
      return RaisedButton(
        onPressed: increment,
        child: Child(),
      );
    },
  );
}
like image 103
Rémi Rousselet Avatar answered Sep 28 '22 04:09

Rémi Rousselet


Selector is what you need. With selector you can filter updates. For example to update only when name change you can do something like this

Selector<AppStore, String>(
  selector: (_, store) => store.name,
  builder: (_, name, __) {
    return Text(name);
  },
);
like image 26
Murat Erdogan Avatar answered Sep 28 '22 04:09

Murat Erdogan