如何在flutter中使用provider时避免不必要的重新渲染?

时间:2019-06-08 09:56:58

标签: flutter dart

我在我的应用程序中使用 provider ,但是我面临不必要的构建。

示例

class MainProviderContainer extends StatelessWidget{
   @override
   Widget build(BuildContext context){
     return ChangeNotifierProvider(
        builder: (context) => ChangeNotifierDataClass(),
        child: Scaffold(
          appBar: AppBar(
             title: Text('Provider Demo')
          ),
          body: Column(
             children: <Widget>[
                MyWidget1(),
                MyWidget2(),
                MyWidget3(),
             ]
          ),
          floatingActionButton: MyFAB();
        )
     )
   }
}

现在,如果我仅更新widget2widget1 & widget3也将得到构建,这是我不想要的。

我在这里担心表现。

所以我的期望是:

我将仅更新(构建)我想要的小部件。因为我认为如果避免不必要的构建,可能会提高性能。

现在,如果有解决方案,请举例说明。 具有react-native功能,可以像shouldComponentUpdate(nextProps, nextState)那样思考,可以用来避免不必要的渲染并提高性能。

3 个答案:

答案 0 :(得分:4)

有多种解决方案:

  • listen: false传递到Provider.of
RaisedButton(
  onPressed: () {
    Provider.of<MyModel>(context, listen: false).increment();
  },
  child: Child(),
);
  • 使用Selector
Selector<MyModel, VoidCallback>(
  selector: (_, model) => model.increment,
  builder: (_, increment) {
    return RaisedButton(
      onPressed: increment,
      child: Child(),
    );
  },
);

答案 1 :(得分:2)

选择器是您所需要的。使用选择器可以过滤更新。 例如,仅在名称更改时进行更新,您可以执行以下操作

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

答案 2 :(得分:1)

我只是通过如下代码来避免不必要的渲染:

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