简体   繁体   English

"使用 Flutter Provider 包 Selector 小部件重建不必要的小部件"

[英]Using Flutter Provider package Selector widget rebuilds unnecessary widgets

When I update a ChangeNotifier class instance variable using Provider.of<T>(context, listen: true).value all Selector widgets dependent on that class are rebuilt (as if I used a Consumer rather than a Selector widget).当我使用Provider.of<T>(context, listen: true).value更新ChangeNotifier类实例变量时,将重建依赖于该类的所有Selector小部件(就像我使用Consumer而不是Selector小部件一样)。 If I update an instance variable using Provider.of<T>(context, listen: false).value the Selector widget and associated selector: parameter correctly update only the widgets dependent upon the changed data如果我使用Provider.of<T>(context, listen: false).value更新实例变量,则Selector小部件和关联的selector:参数仅根据更改的数据正确更新小部件

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() => runApp(AppMain());

class ModState with ChangeNotifier {
  int _counter0 = 0;
  int get counter0 => _counter0;
  set counter0(int _value) {
    _counter0 = _value;
    notifyListeners();
  }

  int _counter1 = 0;
  int get counter1 => _counter1;
  set counter1(int _value) {
    _counter1 = _value;
    notifyListeners();
  }

    int get counter012 => (_counter0 + _counter1);

  static ModState of(BuildContext context, {bool listen = true}) =>
      Provider.of<ModState>(context, listen: listen);
}

class AppMain extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
        providers: [ChangeNotifierProvider(builder: (_) => ModState())],
        child: MaterialApp(home: Scaffold(
            // Wrap in Builder Widget to clarify context
            body: Builder(builder: (context) {
          return SafeArea(
              child: Column(children: <Widget>[
            Row(
              children: <Widget>[
                Tooltip(
                  message: 'Update counter 0, rebuild counter 0 Text widget',
                  child: RaisedButton(
                    onPressed: () {
                      // Counterintuitively, user Provider.of<mode>(context, listen: false) to avoid rebuilding all children
                      ModState.of(context, listen: false).counter0++;
                      debugPrint(
                          'Counter0: button pressed ${ModState.of(context, listen: false).counter0}');
                    },
                    child: Text('Update 0, rebuild 0'),
                  ),
                ),
                Selector<ModState, int>(
                  selector: (_, _state) => _state.counter0,
                  builder: (_, _data, __) {
                    debugPrint(
                        'Counter0, builder invoked ${ModState.of(context, listen: false).counter0}');
                    return Text(
                        '$_data / ${ModState.of(context, listen: false).counter012}');
                  },
                )
              ],
            ),
            Row(
              children: <Widget>[
                Tooltip(
                  message: 'Update counter 1, rebuild counter 1 Text widget',
                  child: RaisedButton(
                    onPressed: () {
                      // Counterintuitively, user Provider.of<mode>(context, listen: false) to avoid rebuilding all children
                      ModState.of(context, listen: false).counter1++;
                      debugPrint(
                          'Counter1: button pressed ${ModState.of(context, listen: false).counter1}');
                    },
                    child: Text('Update 1, rebuild 1'),
                  ),
                ),
                Selector<ModState, int>(
                  selector: (_, _state) => _state.counter1,
                  builder: (_, _data, __) {
                    debugPrint(
                        'Counter1, builder invoked ${ModState.of(context, listen: false).counter1}');
                    return Text(
                        '$_data / ${ModState.of(context, listen: false).counter012}');
                  },
                )
              ],
            ),
          ]));
        }))));
  }
}

While my now code works, using the listen: false parameter is counter-intuitive in terms of my understanding of that parameter.虽然我现在的代码有效,但就我对该参数的理解而言,使用listen: false参数是违反直觉的。 I would like to understand why, so that I can improve my code in general我想了解原因,以便总体上改进我的代码

From what has been mentioned on this post, Selector is working as expected.从这篇文章中提到的内容来看, Selector正在按预期工作。 As mentioned in the docs , the Widget will rebuild when there's a change on selector(BuildContext, A) .文档中所述,当selector(BuildContext, A)发生更改时,小部件将重建。 What seems to happen here is the entire Widget build() gets rebuilt.这里似乎发生的是整个Widget build()被重建。 Then again, if the data displayed on the Widgets are correct and there's no performance issues, then it's passable.再说一次,如果 Widgets 上显示的数据是正确的并且没有性能问题,那么它是可以通过的。 However, if you'd like to prevent rebuilds, you may want to reconsider how Provider is laid out on the page.但是,如果您想阻止重建,您可能需要重新考虑 Provider 在页面上的布局方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM