【问题标题】:Flutter adding to state using RiverpodFlutter 使用 Riverpod 添加到状态
【发布时间】:2021-08-15 11:08:13
【问题描述】:

在搜索并详细了解如何添加或更新数据结构的某些字段后,我们有以下实现

在这里,我们希望有一个简单的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,它们可以作为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 1productId 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);
}

【问题讨论】:

    标签: flutter dart riverpod flutter-freezed


    【解决方案1】:

    你需要做这样的事情。

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

    【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 你自己测试了吗?我不确定,因为我收到错误 Unsupported operation: Cannot add to an unmodifiable list
      • 尝试删除resetOrder中的const
      • 我现在不使用这个功能
      猜你喜欢
      • 2022-09-27
      • 2021-02-10
      • 2021-01-28
      • 2021-08-28
      • 1970-01-01
      • 1970-01-01
      • 2021-03-24
      • 2022-12-16
      • 2021-03-17
      相关资源
      最近更新 更多