使用 Riverpod 将 Flutter 添加到状态
Flutter adding to state using Riverpod
在搜索并详细了解如何添加或更新数据结构的某些字段后,我们有以下实现
这里我们想要一个简单的 order
结构,其中包含用户可以将服务添加到订单或更新所选服务计数的数据,例如,在第一次用户未选择任何服务时,我们有 OrderStructure:[]
我们在 constructor
:
中开头
OrderNotifier() : super(_initial);
static OrderStructure _initial = OrderStructure('', []);
当用户选择任何服务时,我们将三个参数传递给 increment
方法:
void increment({required int productId, required int serviceId, required int serviceCost})
如果服务不存在,应该添加属于产品的服务。每个服务都属于产品,我们用 productId 存储它
在 increment
方法中我们传递 productId
、serviceId
和 serviceCost
,它们可以搜索到 class 数据结构作为 OrderStructure。
如果 productId 存在,那么我们尝试搜索 serviceId,如果 serviceId 存在。 productId = true && serviceId = true
然后我们应该增加 count
值,
如果不存在,则应另存为新项目
请注意,我们不应该将多个相同的 productId
或 serviceId
放入 OrderStructure
.
它们中的每一个都必须是唯一的。每个产品可以有多个服务,例如 List
,OrderStructure
不应该有多个 productId
例如OrderStructure
数据结构可以是:
OrderStructure:
title : 'sample',
products:[
productId: 1
services : [
[serviceId:1, count:1, cost: 100],
[serviceId:2, count:9, cost: 500],
[serviceId:3, count:5, cost: 2000],
],
productId: 2
services : [
[serviceId:3, count:10, cost: 100],
[serviceId:5, count:6, cost: 500]
],
productId: 3
services : [
[serviceId:3, count:10, cost: 100],
[serviceId:5, count:6, cost: 500],
[serviceId:6, count:6, cost: 500],
[serviceId:7, count:6, cost: 500],
[serviceId:8, count:6, cost: 500],
],
]
当用户选择 seriveId
id 1
并且 productId
id 是 1
时,我们在这个集合中搜索 productId
然后 serviceId
, 如果它存在那么 count
应该递增,否则它应该作为一个新的
添加到 OrderStructure
集合中
例如:
OrderStructure:
title : 'sample',
products:[
productId: 1
services : [
[serviceId:1, count:2, cost: 100],
...
我们有这段代码,但它不正确:
void increment({required int productId, required int serviceId, required int serviceCost}) {
final newState = OrderStructure(state.title, [
...state.products,
for (final product in state.products)
if (product.id == productId)
for (final service in product.services)
if (service.id == serviceId)
SelectedProducts(productId,
[...product.services, SelectedProductServices(service.id, service.count + 1, service.cost)])
]);
// ignore: iterable_contains_unrelated_type
if (!newState.products.contains(productId) ||
// ignore: iterable_contains_unrelated_type
!newState.products.firstWhere((p) => p.id == productId).services.contains(serviceId)) {
newState.products.add(
SelectedProducts(serviceId, <SelectedProductServices>[SelectedProductServices(serviceId, 1, serviceCost)]));
}
state = newState;
}
完整代码:
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends ConsumerWidget {
@override
Widget build(BuildContext context,ScopedReader watch) {
final _orderProvider = watch(orderStateNotifierProvider.notifier);
final _product = SelectedProducts(1, []);
final _service = SelectedProductServices(1, 1, 111);
return Scaffold(
appBar: AppBar(
title: Text('test'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
TextButton(
child: Text('add new service'),
onPressed: ()=>context.read(orderStateNotifierProvider.notifier)
.increment(productId:1, serviceId:1, serviceCost:100),
),
// here we want to add new service to product, the same as above code, if productId doesn't exists
// into `OrderStructure` it should be save with
TextButton(
child: Text('append service to product`s services'),
onPressed: ()=>context.read(orderStateNotifierProvider.notifier)
.increment(productId:1, serviceId:2, serviceCost:500),
),
Text('product`s service count: ${_orderProvider.state.products[0].services.length}')
],
),
)
);
}
}
//------------------------
final orderStateNotifierProvider = StateNotifierProvider<OrderNotifier, OrderStructure>((ref) => OrderNotifier());
class OrderNotifier extends StateNotifier<OrderStructure> {
OrderNotifier() : super(_initial);
static OrderStructure _initial = OrderStructure('', []);
void resetOrder() {
_initial = const OrderStructure('', []);
}
void updateAddress({
required String title,
}) {
state = OrderStructure(title,state.products);
}
void increment({required int productId, required int serviceId, required int serviceCost}) {
final newState = OrderStructure(state.title, [
...state.products,
for (final product in state.products)
if (product.id == productId)
for (final service in product.services)
if (service.id == serviceId)
SelectedProducts(productId,
[...product.services, SelectedProductServices(service.id, service.count + 1, service.cost)])
]);
// ignore: iterable_contains_unrelated_type
if (!newState.products.contains(productId) ||
// ignore: iterable_contains_unrelated_type
!newState.products.firstWhere((p) => p.id == productId).services.contains(serviceId)) {
newState.products.add(
SelectedProducts(serviceId, <SelectedProductServices>[SelectedProductServices(serviceId, 1, serviceCost)]));
}
state = newState;
}
}
class OrderStructure {
final String title;
final List<SelectedProducts> products;
const OrderStructure(this.title, this.products);
}
class SelectedProducts {
final int id;
final List<SelectedProductServices> services;
SelectedProducts(this.id, this.services);
}
class SelectedProductServices {
final int id;
final int count;
final int cost;
const SelectedProductServices(this.id, this.count, this.cost);
}
您不需要更新整个 OrderStructure
,只需更新包含要更新的服务的内部列表的引用:
void increment({required int productId, required int serviceId, required int serviceCost}) {
final OrderStructure order = state;
final int productIndex = order.products.indexWhere((product) => product.id == productId);
final SelectedProducts product;
// If the product has not been found, add it to the products
if (productIndex == -1) {
product = SelectedProducts(productId, []);
order.products.add(product);
// Otherwise, just get it
} else {
product = order.products[productIndex];
}
final int serviceIndex = product.services.indexWhere((service) => service.id == serviceId && service.cost == serviceCost);
// If the service has not been found, add it to the services
if (serviceIndex == -1) {
product.services.add(SelectedProductServices(serviceId, 1, serviceCost));
// Otherwise, just update its counter
} else {
final SelectedProductServices service = product.services[serviceIndex];
product.services[serviceIndex] = SelectedProductServices(service.id, service.count + 1, service.cost);
}
// Set the state to the updated order structure
state = order;
}
对于递减部分,在最后一行做service.count - 1
即可。
我修复了问题,increment
方法应该是:
void increment(int productId, int serviceId, int serviceCost) {
final newState = OrderStructure(state.title, state.address, state.lat, state.lang, state.pelak, state.vahed, []);
for (final product in state.products) {
if (product.id == productId) {
if (product.services.any((s) => s.id == serviceId)) {
final service = product.services.firstWhere((s) => s.id == serviceId);
newState.products.add(SelectedProducts(productId, [
...product.services.where((s) => s.id != serviceId),
SelectedProductServices(service.id, service.count + 1, service.cost)
]));
} else {
newState.products.add(
SelectedProducts(productId, [...product.services, SelectedProductServices(serviceId, 1, serviceCost)]));
}
} else {
newState.products.add(product);
}
}
if (!newState.products.any((p) => p.id == productId) ||
!newState.products.firstWhere((p) => p.id == productId).services.any((s) => s.id == serviceId)) {
// Add new
newState.products.add(SelectedProducts(productId, [SelectedProductServices(serviceId, 1, serviceCost)]));
}
state = newState;
}
感谢 TimWhiting
你需要做这样的事情。
void increment(int productId, int serviceId, int serviceCost) {
// copy the old state
final newState = OrderStructure(state.title, [...state.products]);
bool updated = false;
/// We directly iterate on the newState.
for(final product in newState.products){
if( product.id != productId ) {
continue; // jump to next the product because the current product do not match.
}
updated = true; // We are sure that the product already exist.
// We search the first index of service that has `id` equal to `serviceId`.
final serviceIndex = product.services.indexWhere( (s) => s.id == serviceId );
if( serviceIndex >= 0 ) {
product.services[serviceIndex].count ++;
break;
}
final newService = SelectedProductServices(serviceId, 1, serviceCost);
product.services.add(newService);
break;
}
// Now we only check if we have not made an update.
if(!update) {
final newService = SelectedProductServices(serviceId, 1, serviceCost);
final newProduct = SelectedProduct(productId, [newService]);
newState.products.add(newProduct);
}
}
在搜索并详细了解如何添加或更新数据结构的某些字段后,我们有以下实现
这里我们想要一个简单的 order
结构,其中包含用户可以将服务添加到订单或更新所选服务计数的数据,例如,在第一次用户未选择任何服务时,我们有 OrderStructure:[]
我们在 constructor
:
OrderNotifier() : super(_initial);
static OrderStructure _initial = OrderStructure('', []);
当用户选择任何服务时,我们将三个参数传递给 increment
方法:
void increment({required int productId, required int serviceId, required int serviceCost})
如果服务不存在,应该添加属于产品的服务。每个服务都属于产品,我们用 productId 存储它
在 increment
方法中我们传递 productId
、serviceId
和 serviceCost
,它们可以搜索到 class 数据结构作为 OrderStructure。
如果 productId 存在,那么我们尝试搜索 serviceId,如果 serviceId 存在。 productId = true && serviceId = true
然后我们应该增加 count
值,
如果不存在,则应另存为新项目
请注意,我们不应该将多个相同的 productId
或 serviceId
放入 OrderStructure
.
它们中的每一个都必须是唯一的。每个产品可以有多个服务,例如 List
,OrderStructure
不应该有多个 productId
例如OrderStructure
数据结构可以是:
OrderStructure:
title : 'sample',
products:[
productId: 1
services : [
[serviceId:1, count:1, cost: 100],
[serviceId:2, count:9, cost: 500],
[serviceId:3, count:5, cost: 2000],
],
productId: 2
services : [
[serviceId:3, count:10, cost: 100],
[serviceId:5, count:6, cost: 500]
],
productId: 3
services : [
[serviceId:3, count:10, cost: 100],
[serviceId:5, count:6, cost: 500],
[serviceId:6, count:6, cost: 500],
[serviceId:7, count:6, cost: 500],
[serviceId:8, count:6, cost: 500],
],
]
当用户选择 seriveId
id 1
并且 productId
id 是 1
时,我们在这个集合中搜索 productId
然后 serviceId
, 如果它存在那么 count
应该递增,否则它应该作为一个新的
OrderStructure
集合中
例如:
OrderStructure:
title : 'sample',
products:[
productId: 1
services : [
[serviceId:1, count:2, cost: 100],
...
我们有这段代码,但它不正确:
void increment({required int productId, required int serviceId, required int serviceCost}) {
final newState = OrderStructure(state.title, [
...state.products,
for (final product in state.products)
if (product.id == productId)
for (final service in product.services)
if (service.id == serviceId)
SelectedProducts(productId,
[...product.services, SelectedProductServices(service.id, service.count + 1, service.cost)])
]);
// ignore: iterable_contains_unrelated_type
if (!newState.products.contains(productId) ||
// ignore: iterable_contains_unrelated_type
!newState.products.firstWhere((p) => p.id == productId).services.contains(serviceId)) {
newState.products.add(
SelectedProducts(serviceId, <SelectedProductServices>[SelectedProductServices(serviceId, 1, serviceCost)]));
}
state = newState;
}
完整代码:
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends ConsumerWidget {
@override
Widget build(BuildContext context,ScopedReader watch) {
final _orderProvider = watch(orderStateNotifierProvider.notifier);
final _product = SelectedProducts(1, []);
final _service = SelectedProductServices(1, 1, 111);
return Scaffold(
appBar: AppBar(
title: Text('test'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
TextButton(
child: Text('add new service'),
onPressed: ()=>context.read(orderStateNotifierProvider.notifier)
.increment(productId:1, serviceId:1, serviceCost:100),
),
// here we want to add new service to product, the same as above code, if productId doesn't exists
// into `OrderStructure` it should be save with
TextButton(
child: Text('append service to product`s services'),
onPressed: ()=>context.read(orderStateNotifierProvider.notifier)
.increment(productId:1, serviceId:2, serviceCost:500),
),
Text('product`s service count: ${_orderProvider.state.products[0].services.length}')
],
),
)
);
}
}
//------------------------
final orderStateNotifierProvider = StateNotifierProvider<OrderNotifier, OrderStructure>((ref) => OrderNotifier());
class OrderNotifier extends StateNotifier<OrderStructure> {
OrderNotifier() : super(_initial);
static OrderStructure _initial = OrderStructure('', []);
void resetOrder() {
_initial = const OrderStructure('', []);
}
void updateAddress({
required String title,
}) {
state = OrderStructure(title,state.products);
}
void increment({required int productId, required int serviceId, required int serviceCost}) {
final newState = OrderStructure(state.title, [
...state.products,
for (final product in state.products)
if (product.id == productId)
for (final service in product.services)
if (service.id == serviceId)
SelectedProducts(productId,
[...product.services, SelectedProductServices(service.id, service.count + 1, service.cost)])
]);
// ignore: iterable_contains_unrelated_type
if (!newState.products.contains(productId) ||
// ignore: iterable_contains_unrelated_type
!newState.products.firstWhere((p) => p.id == productId).services.contains(serviceId)) {
newState.products.add(
SelectedProducts(serviceId, <SelectedProductServices>[SelectedProductServices(serviceId, 1, serviceCost)]));
}
state = newState;
}
}
class OrderStructure {
final String title;
final List<SelectedProducts> products;
const OrderStructure(this.title, this.products);
}
class SelectedProducts {
final int id;
final List<SelectedProductServices> services;
SelectedProducts(this.id, this.services);
}
class SelectedProductServices {
final int id;
final int count;
final int cost;
const SelectedProductServices(this.id, this.count, this.cost);
}
您不需要更新整个 OrderStructure
,只需更新包含要更新的服务的内部列表的引用:
void increment({required int productId, required int serviceId, required int serviceCost}) {
final OrderStructure order = state;
final int productIndex = order.products.indexWhere((product) => product.id == productId);
final SelectedProducts product;
// If the product has not been found, add it to the products
if (productIndex == -1) {
product = SelectedProducts(productId, []);
order.products.add(product);
// Otherwise, just get it
} else {
product = order.products[productIndex];
}
final int serviceIndex = product.services.indexWhere((service) => service.id == serviceId && service.cost == serviceCost);
// If the service has not been found, add it to the services
if (serviceIndex == -1) {
product.services.add(SelectedProductServices(serviceId, 1, serviceCost));
// Otherwise, just update its counter
} else {
final SelectedProductServices service = product.services[serviceIndex];
product.services[serviceIndex] = SelectedProductServices(service.id, service.count + 1, service.cost);
}
// Set the state to the updated order structure
state = order;
}
对于递减部分,在最后一行做service.count - 1
即可。
我修复了问题,increment
方法应该是:
void increment(int productId, int serviceId, int serviceCost) {
final newState = OrderStructure(state.title, state.address, state.lat, state.lang, state.pelak, state.vahed, []);
for (final product in state.products) {
if (product.id == productId) {
if (product.services.any((s) => s.id == serviceId)) {
final service = product.services.firstWhere((s) => s.id == serviceId);
newState.products.add(SelectedProducts(productId, [
...product.services.where((s) => s.id != serviceId),
SelectedProductServices(service.id, service.count + 1, service.cost)
]));
} else {
newState.products.add(
SelectedProducts(productId, [...product.services, SelectedProductServices(serviceId, 1, serviceCost)]));
}
} else {
newState.products.add(product);
}
}
if (!newState.products.any((p) => p.id == productId) ||
!newState.products.firstWhere((p) => p.id == productId).services.any((s) => s.id == serviceId)) {
// Add new
newState.products.add(SelectedProducts(productId, [SelectedProductServices(serviceId, 1, serviceCost)]));
}
state = newState;
}
感谢 TimWhiting
你需要做这样的事情。
void increment(int productId, int serviceId, int serviceCost) {
// copy the old state
final newState = OrderStructure(state.title, [...state.products]);
bool updated = false;
/// We directly iterate on the newState.
for(final product in newState.products){
if( product.id != productId ) {
continue; // jump to next the product because the current product do not match.
}
updated = true; // We are sure that the product already exist.
// We search the first index of service that has `id` equal to `serviceId`.
final serviceIndex = product.services.indexWhere( (s) => s.id == serviceId );
if( serviceIndex >= 0 ) {
product.services[serviceIndex].count ++;
break;
}
final newService = SelectedProductServices(serviceId, 1, serviceCost);
product.services.add(newService);
break;
}
// Now we only check if we have not made an update.
if(!update) {
final newService = SelectedProductServices(serviceId, 1, serviceCost);
final newProduct = SelectedProduct(productId, [newService]);
newState.products.add(newProduct);
}
}