繁体   English   中英

Flutter 使用 Riverpod 添加到 state

[英]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方法中,我们传递productIdserviceIdserviceCost ,它可以搜索到 class 数据结构作为 OrderStructure。

如果 productId 存在,那么我们尝试搜索 serviceId,如果 serviceId 存在。 productId = true && serviceId = true然后我们应该增加count数值,如果它不存在它应该另存为新项目注意我们不应该将多个相同的productIdserviceId放入OrderStructure中。

他们每个人都必须是独一无二的。 每个产品可以有多个服务,例如ListOrderStructure不应该有多个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);
}

你需要做这样的事情。

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); 
  }
}

我修复了问题, 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

您不需要更新整个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即可。

暂无
暂无

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

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