Flutter选择器优化插件reselect的使用

发布于 1周前 作者 phonegap100 来自 Flutter

Flutter选择器优化插件reselect的使用

Reselect for Dart

Build Status codecov

Reselect是一个为Dart编写的Selector库,基于原始的Reselect JavaScript库

  • 选择器(Selectors):从单个输入(如Redux Store的状态)派生数据的函数。
  • 单点访问:提供对Redux Store中数据的单一入口。
  • 计算派生数据:允许Redux存储最小可能状态。
  • 高效性:只有在参数变化时才会重新计算派生数据。
  • 可组合性:可以组合以创建更复杂的选择器。

注意:此库和示例是针对Redux的,但也可以与任何Redux实现或数据源一起使用。

安装

请参阅包页面上的安装说明:https://pub.dartlang.org/packages/reselect#pub-pkg-tab-installing

示例

动机

让我们通过一个简单的Redux示例来解释我们的动机。假设我们有一个AppState,它保存了一个产品列表和商店名称。我们希望显示所有打折的产品,并且还需要过滤出价格低于10美元的产品。

// 定义Product类
class Product {
  String name;
  bool onSale;
  double price;

  Product(this.name, this.price, [this.onSale = false]);

  // 辅助构造函数,用于创建打折商品
  factory Product.onSale(String name, double price) => Product(name, price, true);
}

// 创建一个包含应用状态的类
class AppState {
  final String shopName;
  final List<Product> products;

  AppState(this.shopName, this.products);
}

// 创建应用状态
final appState = AppState("Brian's Keyboard Stop", [
  Product("Cherry Mx Red switch", 14.99),
  Product("Cherry Mx Blue switch", 9.99),
  Product.onSale("Cherry Mx Brown switch", 8.99),
]);

// 创建一个查找打折产品的函数
final selectOnSaleProduct = (AppState state) =>
    state.products.where((product) => product.onSale);

// 创建一个查找价格低于10美元的产品的函数
final affordableProductsSelector = (AppState state) =>
    state.products.where((product) => product.price < 10.00);

创建单点访问

现在,我们将创建一个选择器函数,用于从应用状态中选择产品,作为单点访问。

// 创建一个选择器函数,用于从AppState中选择产品
final productsSelector = (AppState state) => state.products;

// 使用单点访问更新之前的筛选函数
final selectOnSaleProduct = (AppState state) =>
    productsSelector(state).where((product) => product.onSale);

// 查找价格低于10美元的产品
final affordableProductsSelector = (AppState state) =>
    productsSelector(state).where((product) => product.price < 10.00);

缓存计算值

接下来,我们将使用createSelector1createSelector10函数来缓存计算结果。

// 计算所有打折产品,仅当产品列表发生变化时才重新计算
final onSaleSelector = createSelector1(
  productsSelector,
  (products) => products.where((product) => product.onSale),
);

// 缓存查找价格低于10美元的产品的函数
final affordableProductsSelector = createSelector1(
  productsSelector,
  (products) => products.where((product) => product.price < 10.00),
);

// 打印所有打折产品
print(onSaleSelector(appState));

// 再次打印,如果产品未变化,则返回缓存的结果
print(onSaleSelector(appState));

组合选择器

现在,我们将组合两个缓存的选择器,创建一个新的选择器。

// 使用`createSelector2`组合两个选择器
final snapDealsSelector = createSelector2(
  onSaleSelector,
  affordableProductsSelector,
  (onSaleProducts, affordableProducts) =>
      ([]..addAll(onSaleProducts)..addAll(affordableProducts)),
);

总结

我们已经:

  • 将直接访问AppState中的产品改为使用选择器作为单点访问。
  • 使用createSelector1缓存昂贵的选择器,以便仅在依赖的数据变化时重新计算。
  • 使用createSelector2组合两个缓存的选择器,创建新的缓存选择器。

更多内容

更改缓存机制

默认的缓存函数来自memoize包,使用==方法确定输入是否变化。如果需要更改其工作方式,可以提供自己的缓存函数。

// 提供自定义的缓存函数,比较输入的身份而不是使用`==`方法
final onSaleSelector = createSelector1(
  productsSelector,
  (products) => products.where((product) => product.onSale),
  memoize: (Func1<List<Product>, List<Product>> combiner) {
    List<Product> prevProductsArg;
    List<Product> prevOnSaleProducts;

    return ((List<Product> productsArg) {
      if (identical(productsArg, prevProductsArg)) {
        return prevOnSaleProducts;
      } else {
        prevProductsArg = productsArg;
        prevOnSaleProducts = combiner(productsArg);

        return prevOnSaleProducts;
      }
    });
  },
);

这就是如何使用reselect库优化Flutter中的选择器。通过这些步骤,您可以创建更健壮、高效的代码结构。


更多关于Flutter选择器优化插件reselect的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter选择器优化插件reselect的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter开发中,reselect 是一个灵感来自 Redux 的 reselect 库的强大工具,它用于创建高效的、可缓存的选择器(selectors)。虽然 reselect 最初是为 Redux 设计的,但类似的概念也可以应用到 Flutter 的状态管理中,特别是当你使用像 ProviderRiverpod 这样的状态管理库时。

在 Flutter 中,通过 reselect 或类似的概念优化选择器的主要目的是避免不必要的计算,特别是在处理复杂的数据转换或派生状态时。这可以通过创建可记忆的选择器来实现,这些选择器只在依赖的数据发生变化时重新计算。

下面是一个简化的例子,展示了如何在 Flutter 应用中使用类似 reselect 的概念来优化选择器。我们将使用 provider_architecture 包中的 Selector 作为示例,尽管它不是 reselect 的直接实现,但原理相似。

首先,确保你已经在 pubspec.yaml 中添加了必要的依赖:

dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.0  # 确保使用最新版本

然后,我们可以创建一个简单的 Flutter 应用,演示如何使用优化选择器。

示例代码

main.dart

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

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => UserData()),
      ],
      child: MyApp(),
    ),
  );
}

class UserData extends ChangeNotifier {
  String _name = 'Alice';
  int _age = 30;

  String get name => _name;
  int get age => _age;

  void updateName(String newName) {
    _name = newName;
    notifyListeners();
  }

  void updateAge(int newAge) {
    _age = newAge;
    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Reselect Example')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Selector<UserData, String>(
                selector: (_, userData) => userData.name,
                builder: (_, name, __) {
                  return Text('Name: $name');
                },
              ),
              Selector<UserData, int>(
                selector: (_, userData) => userData.age,
                builder: (_, age, __) {
                  return Text('Age: $age');
                },
              ),
              ElevatedButton(
                onPressed: () {
                  final userData = Provider.of<UserData>(context, listen: false);
                  userData.updateName('Bob');
                },
                child: Text('Update Name'),
              ),
              ElevatedButton(
                onPressed: () {
                  final userData = Provider.of<UserData>(context, listen: false);
                  userData.updateAge(35);
                },
                child: Text('Update Age'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

解释

  1. UserData 类:这是一个 ChangeNotifier,它包含用户的姓名和年龄,并提供方法来更新这些数据。

  2. MultiProvider:我们在应用的顶层使用 MultiProvider 来提供 UserData

  3. Selector:我们使用 Selector 小部件来选择 UserData 中的特定属性(姓名和年龄)。Selector 小部件只在依赖的数据发生变化时重建其子小部件。

  4. 按钮:我们有两个按钮,一个用于更新姓名,另一个用于更新年龄。点击按钮会触发 UserData 中的通知,从而只更新依赖于变化数据的 Selector

通过这种方式,我们避免了不必要的重建,因为每个 Selector 只关心它自己的数据片段。这与 reselect 在 Redux 中的工作方式类似,都是为了提高性能和效率。

请注意,虽然 Flutter 社区中没有官方的 reselect 实现,但你可以使用类似 Selector 的小部件或自定义逻辑来实现类似的功能。

回到顶部