Search code examples
flutterdartprovider

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.


Solution

  • I just avoided unnecessary rendering by editing my code as the following:

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