Управление состоянием Flutter: руководство по началу работы с Provider4 (3)

Flutter

предисловие

Мне очень жаль, проект в последнее время слишком загружен, поэтому обновление идет слишком медленно. Без дальнейших церемоний, давайте начнем.

Selector

Чтение документов

Вообще-то я не собирался говоритьSelectorДа, но друг хочет, чтобы я представил его, так что начни сSelectorНачинать.

В основном,Selectorа такжеConsumerэквивалентно, такжеProvider.ofОтличие получения данных в том, что,SelectorКак следует из его имени, он будет отфильтровывать ненужное обновление данных, чтобы предотвратить перестроение, то естьSelectorБудут обновлены только подходящие данные.

Давайте сначала посмотримSelectorОпределение:

class Selector<A, S> extends Selector0<S> {
  /// {@macro provider.selector}
  Selector({
    Key key,
    @required ValueWidgetBuilder<S> builder,
    @required S Function(BuildContext, A) selector,
    ShouldRebuild<S> shouldRebuild,
    Widget child,
  })  : assert(selector != null),
        super(
          key: key,
          shouldRebuild: shouldRebuild,
          builder: builder,
          selector: (context) => selector(context, Provider.of(context)),
          child: child,
        );
}

сначала объясниSelector<A, S>Дженерики в:

  • Aэто то, что мы получаем от верхнего уровняProviderтип
  • SЭто конкретный вид заботы, то есть получается.ProviderТипы, которые действительно полезны для нас, должны быть вselectorвозвращает этот тип в . этоSelectorДиапазон обновления также из всегоProviderстал С.

бросить быстрый взглядSelectorсвойства в:

  • селектор: этоFunction, выйдя на верхний уровень получимproviderпередать, а затем вернуть то, что нам небезразличноS.
  • shouldRebuild: это свойство будет сохраненоselectorОтфильтрованное значение, т.е.selectorвернутьSи взять новый после получения уведомленияSс кэшемSсравнивать, судить об этомSelectorНужно ли перестраивать, по умолчаниюpreview!=nextпросто обновите, если этоcollection,selectorСравнение глубины.
  • строитель: иConsumerТо же самое, здесь возвращается элемент управления, который нужно построить, второй параметрprovider, что мы только чтоselectorвернулся вS.
  • дочерний: Это обновление для оптимизации некоторой неиспользуемой части, прежде чем мы скажемConsumerтакже сказал в то время.

по умолчанию,SelectorсерединаbuilderБудет ли вызвано обновление, зависит отselectorСравните результат между старыми и новыми данными, если старые и новые данныеcollection, то этот результат сравнения получаетсяcollectionв упаковкеDeepCollectionEqualityРезультат.

Это поведение по умолчанию может быть настроеноshouldRebuildОбратный вызов на переписать.

Примечание. Выбранные данные должны быть неизменяемыми, иначеSelectorМожно подумать, что ничего не изменилось, поэтому застройщика больше вызывать не будут.

так,selectorДолжен вернуть коллекцию (List/Map/Set/Iterable) или переопределить==тип.

Но иногда мы не хотим переписать==, самый простой способ добиться того же эффекта — использоватьTuple:

Selector<Foo, Tuple2<Bar, Baz>>(
  selector: (_, foo) => Tuple2(foo.bar, foo.baz),
  builder: (_, data, __) {
    return Text('${data.item1}  ${data.item2}');
  }
)

В приведенном выше примере толькоfoo.barилиfoo.barкогда происходят изменения,builderбудет вызван снова.

Подключитесь на то, как использовать конкретные, вы можете узнать самостоятельно.

Например

То, что я сказал выше, не более чем список официальных документов, поговорим о конкретных приложениях.

Кратко о функции, которую мы хотим реализовать.Она очень проста.Есть список товаров.При нажатии на товар,товар добавится в корзину. Эта функция на самом деле очень проста, нам нужноCommodityУстановить, добавляется ли поле в корзинуisSelected, затем, когда мы нажимаем на элемент, мы хотим обновитьisSelectedПоле, то мы, безусловно, заметимFlutterОбновите пользовательский интерфейс, если используетеChangeNotifier, то есть звонитьnotifyListeners. Это может удовлетворить наши потребности, но если хорошо подумать, если использовать этот способ, то все зависимости, которые зависят от этого ProviderCommodityОн будет обновлен, и весь список будет обновлен, это действительно необходимо?

В настоящее время мы можем рассмотреть возможность использованияSelectorСделайте оптимизацию - отфильтровать ненужные обновления.

Во-первых, мы создаемCommodityProvider:

class CommodityProvider with ChangeNotifier {
  List<Commodity> _commodityList =
      List.generate(10, (index) => Commodity('Commodity Name_$index', false));

  get commodityList => _commodityList;

  get length => commodityList.length;

  addToCart(int index) {
    Commodity commodity = commodityList[index];
    commodityList[index] = Commodity(commodity.name, !commodity.isSelected);
    notifyListeners();
  }
}

CommodityЭтот класс сущности очень прост, всего два поля, одно из которых — название продукта.name, другой - пометить, добавлено ли в корзинуisSelected. в_commodityListВ реальной работе он вообще получается с сервера.Здесь мы его прямо пишем до смерти для удобства. а такжеaddToCartМетод заключается в добавлении или удалении из корзины, при нажатии на соответствующийindex, мы добавим этот товар в корзину или удалим его из нее. мы проходим черезcommodityListдля отображения всего списка, в то время какlengthдлина списка элементов.

Далее мы станем свидетелямиSelectorРеально ли обновить фильтр. Далее нам еще предстоит пройти на страницу верхнего уровняChangeNotifierProviderпредоставить данные.

class CommodityListScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_)=>CommodityProvider(),
      child: ourWidget,
    );
  }
}

Очевидно, что для реализации этого списка мы должны знать длину спискаlength,а такжеlengthОн работает со всем списком, но мы не хотим, чтобы он обновлялся из-за изменения определенного элемента в списке, поэтому теперь нам нужно отфильтровать все обновления,SelectorРеализуйте «Потребителя», который не обновляется.

    Selector<CommodityProvider, CommodityProvider>(
        shouldRebuild: (pre, next) => false,
        selector: (_, provider) => provider,
        builder: (context, provider, child) {
          print("build selector 1");
          return ourWidget;
        },
      ),

это здесь,SelectorДженерики вAа такжеSобеCommodityProvider, потому что мы хотим получить всюCommodityProvider, но мы ставимshouldRebuildПереписано, чтобы избежать ненужных обновлений.

Далее мы реализуем наш список продуктов:

ListView.builder(
              itemCount: provider.length,
              itemBuilder: (BuildContext context, int index) =>
                  Selector<CommodityProvider, Commodity>(
                    selector:
                        (BuildContext context, CommodityProvider provider) =>
                            provider.commodityList[index],
                    builder: (BuildContext context, Commodity commodity,
                        Widget child) {
                      print("build item $index");
                      return ListTile(
                        onTap: () => provider.addToCart(index),
                        title: Text("${commodity.name}"),
                        trailing: Icon(commodity.isSelected
                            ? Icons.remove_shopping_cart
                            : Icons.add_shopping_cart),
                      );
                    },
                  ));
        }

мы можем видеть здесьselectorвернулсяprovider.commodityList[index], то есть конкретный товар, поэтому каждый товар должен заботиться только о своей трети земли, что нормально.SelectorОбласть обновления ограничена текущим элементом, пока мы находимся вSelector<CommodityProvider, Commodity>изbuilderДобавлен журнал для проверки механизма обновления фильтра.

Давай, запусти его, кликни по нескольким пунктам, а потом посмотри лог:

I/flutter (29438): build selector 1
I/flutter (29438): build item 0
I/flutter (29438): build item 1
I/flutter (29438): build item 2
I/flutter (29438): build item 3
I/flutter (29438): build item 4
I/flutter (29438): build item 5
I/flutter (29438): build item 6
I/flutter (29438): build item 7
I/flutter (29438): build item 8
I/flutter (29438): build item 9
I/flutter (29438): build item 7
I/flutter (29438): build item 5
I/flutter (29438): build item 4

как насчет этого? Теперь, когда мы обновляем только те элементы, по которым щелкнули, избегая обновления всего списка, мы на небольшой шаг приблизились к оптимизации производительности.

Если вы хотите узнать будущее, пожалуйста, послушайте следующую разбивку

так какProviderТретья статья в серии, содержание по-прежнему очень простое, и я должен сказать, что время ограничено.

Продолжение следует. . . Ожидать или не ожидать, что последнее слово будет за вами.