web-dev-qa-db-fra.com

Comment éviter les reconstructions inutiles lors de l'utilisation du fournisseur dans Flutter?

J'utilise fournisseur dans mon application, mais j'ai dû faire face à une construction inutile.

Exemple

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

  }
}

Maintenant, si je clique sur le widget MyIncreaseButton, pour augmenter la valeur, le widget MyDecreaseButton se construit également, même lorsque je ne clique pas dessus.

Et vice versa, si je clique sur le widget MyDecreaseButton, pour diminuer la valeur, le widget MyIncreaseButton se construit également, même lorsque je ne clique pas dessus.

Mon attente est:

Lorsque vous cliquez sur MyIncreaseButton widget, MyDecreaseButton widget ne doit pas être construit.

9
Muhammad

J'ai juste évité un rendu inutile en modifiant mon code comme suit:

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 increament() {
    _num = _num + 1;
    notifyListeners();
  }

  void decreament() {
    _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.increament(),
    );
  }
}

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.decreament(),
    );
  }
}
2
Muhammad

Le sélecteur est ce dont vous avez besoin. Avec le sélecteur, vous pouvez filtrer les mises à jour. Par exemple, pour mettre à jour uniquement lorsque le nom change, vous pouvez faire quelque chose comme ça

Selector<AppStore, String>(
  selector: (_, store) => store.name,
  builder: (_, name, __) {
    return Text(name);
  },
);
7
Murat Erdogan

Il existe plusieurs solutions:

  • passer listen: false à Provider.of:
RaisedButton(
  onPressed: () {
    Provider.of<MyModel>(context, listen: false).increment();
  },
  child: Child(),
);
  • utilisez Selector:
Selector<MyModel, VoidCallback>(
  selector: (_, model) => model.increment,
  builder: (_, increment) {
    return RaisedButton(
      onPressed: increment,
      child: Child(),
    );
  },
);
7
Rémi Rousselet