【问题标题】:How to avoid unnecessary rebuilds while using provider in flutter?在颤振中使用提供者时如何避免不必要的重建?
【发布时间】:2019-10-23 14:37:08
【问题描述】:

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

例子

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

  }
}

现在,如果我点击 MyIncreaseButton 小部件来增加值,MyDecreaseButton 小部件也会构建,即使我没有点击它。

反之亦然,如果我单击 MyDecreaseButton 小部件以减小值,MyIncreaseButton 小部件也会构建,即使我没有点击它。

我的期望是:

当点击MyIncreaseButton 小部件时,MyDecreaseButton 小部件不应构建。

【问题讨论】:

  • 你的例子不清楚。你能证明一些实际运行的东西吗?
  • @RémiRousselet,您好,谢谢您,请再次查看我编辑过的问题。如您所见,我有树小部件,如果更新小部件2,我想要,所以如果您使用过react-native,则只有这个小部件应该是构建(渲染)而不是小部件1和小部件3,有一个名为shouldcomponentupdate(np, ns)的生命周期函数可以让我们避免不属于那个的不必要的渲染。
  • ​为什么我担心一个大列表,其中每个项目都是一个小部件,所以为什么我问这个问题:认为我的 ListView 有 1000 个项目,我只更新列表中的一个项目,然后这里列表的整个项目都得到重建。在任何更新上重建 1000 个项目可能会降低应用程序性能。
  • “如果只更新 widget2”是什么意思?
  • 我的意思是,让我告诉你什么问题。我有聊天应用程序,我正在使用 ListView 我的 ListView 的每个项目都是widget 所以当我滚动以前的消息时有超过 2000 个项目然后当我删除一条消息时(我只更新一个小部件)这里当我更新一条消息(一个小部件)时,整个列表项都会重建这是我的应用程序在删除后响应速度很慢如果我删除第二条消息,它的工作速度会有点慢

标签: flutter dart provider


【解决方案1】:

有多种解决方案:

  • 使用context.read 或将listen: false 传递给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(),
      );
    },
  );
}

【讨论】:

  • 谢谢你,我已经按照你的说法进行了编辑,我通过了listen: false,但每次点击仍然会重建所有三个小部件。如果我仍然错了,请查看答案。
  • 我面临同样的问题。在我的情况下,我在 StreamBuilder 中有一个选择器,当我调用/更改由选择标记的值时,整个小部件树会重建,我希望只有选择器小部件应该重建。
  • @Muhammad 如果有的话,您是如何解决这个问题的?谢谢
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2022-01-15
      • 1970-01-01
      • 2021-11-01
      • 2019-12-08
      • 2021-01-28
      • 2022-08-19
      • 2020-06-06
      • 2020-10-18
      • 2020-05-10
      相关资源
      最近更新 更多