Flutter选择器优化插件reselect的使用
Flutter选择器优化插件reselect的使用
Reselect for Dart
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);
缓存计算值
接下来,我们将使用createSelector1
到createSelector10
函数来缓存计算结果。
// 计算所有打折产品,仅当产品列表发生变化时才重新计算
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
更多关于Flutter选择器优化插件reselect的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter开发中,reselect
是一个灵感来自 Redux 的 reselect
库的强大工具,它用于创建高效的、可缓存的选择器(selectors)。虽然 reselect
最初是为 Redux 设计的,但类似的概念也可以应用到 Flutter 的状态管理中,特别是当你使用像 Provider
或 Riverpod
这样的状态管理库时。
在 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'),
),
],
),
),
),
);
}
}
解释
-
UserData 类:这是一个
ChangeNotifier
,它包含用户的姓名和年龄,并提供方法来更新这些数据。 -
MultiProvider:我们在应用的顶层使用
MultiProvider
来提供UserData
。 -
Selector:我们使用
Selector
小部件来选择UserData
中的特定属性(姓名和年龄)。Selector
小部件只在依赖的数据发生变化时重建其子小部件。 -
按钮:我们有两个按钮,一个用于更新姓名,另一个用于更新年龄。点击按钮会触发
UserData
中的通知,从而只更新依赖于变化数据的Selector
。
通过这种方式,我们避免了不必要的重建,因为每个 Selector
只关心它自己的数据片段。这与 reselect
在 Redux 中的工作方式类似,都是为了提高性能和效率。
请注意,虽然 Flutter 社区中没有官方的 reselect
实现,但你可以使用类似 Selector
的小部件或自定义逻辑来实现类似的功能。