You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Riverpod的State Notifier实现购物车:数据库数据加载咨询

使用Riverpod整合数据库数据到购物车State Notifier的实现方案

我正在尝试用Riverpod实现购物车功能,想知道怎么从数据库获取商品数据并整合到State Notifier里。我预想的步骤是:

  • 向State Notifier发起购物车数据请求
  • 创建更新方法来更新本地购物车
  • 应用重启后回到步骤1重新获取数据

以下是我的相关代码实现:

我的cart_controller(需从数据库获取数据)

class CartRepository extends Notifier<Map<String, CartItem>> {
  @override
  Map<String, CartItem> build() {
    return {};
  }

  void addItem(
      {required String productId, price, itemsName, name, itemsImage}) {
    if (state.containsKey(productId)) {
      state.update(
          productId,
          (value) => CartItem(
              productId: value.productId,
              itemsName: value.itemsName,
              price: value.price,
              itemsImage: value.itemsImage,
              qty: value.qty! + 1));
    }
    if (!state.containsKey(productId)) {
      state.putIfAbsent(
        productId,
        () => CartItem(
            productId: productId,
            itemsName: itemsName,
            price: price,
            itemsImage: itemsImage,
            qty: 1),
      );
    }
    ref.notifyListeners();
  }

}

final cartRepositoryProvider =
    NotifierProvider<CartRepository, Map<String, CartItem>>(CartRepository.new);

我的请求代码

class CartRepository {
  Map<String, CartItem> cart = {};
  Future<Map<String, CartItem>> getCartRequest() async {
    try {
      final box = Hive.box(Constants.authStorageKey);
      final token = box.get('token');
      final url =
          Uri.parse('http://192.168.1.9:5000/api/v1/products/getcartItems');
      final headers = {
        "Authorization": "Bearer $token",
      };
      final response = await http.get(url, headers: headers);
      if (response.statusCode == 200) {
        final jsonData = json.decode(response.body)['product'];

        for (var productData in jsonData) {
          CartItem product = CartItem.fromJson(
              productData); // Replace with your own deserialization logic
          print(product);
        }
      }
      return cart;
    } catch (e) {
      return cart;
      print(e);
    }
  }
}

final remoteCartRepository = Provider((ref) => CartRepository());

final productsListProvider = FutureProvider<Map<String, CartItem>>((ref) async {
  final repository = ref.watch(remoteCartRepository);
  return repository.getCartRequest();
});

我的CartItem模型

class CartItem {
  String? productId;
  String? itemsName;
  String? price;
  String? itemsImage;
  int? qty;

  CartItem({
    required this.productId,
    required this.itemsName,
    required this.price,
    required this.itemsImage,
    required this.qty,
  });
  CartItem.fromJson(Map<String, dynamic> json) {
    productId = json['itemsId'];
    itemsName = json['itemsName'];
    itemsImage = json['itemsImage'];
    price = json['itemsPrice'];
  }
}

整合解决方案

1. 合并重复类并重构逻辑

你当前存在两个同名的CartRepository类,会导致冲突,需要将数据请求与状态管理合并到同一个Notifier类中,同时修复状态更新的正确方式(Riverpod要求通过替换整个state对象更新状态,不能直接修改原state)。

2. 修改后的完整代码

合并后的CartRepository(状态管理+数据请求)
class CartRepository extends Notifier<Map<String, CartItem>> {
  @override
  Map<String, CartItem> build() {
    // 应用启动/重启时自动加载远程购物车数据
    _loadCartFromRemote();
    return {};
  }

  // 从远程接口获取购物车数据并更新状态
  Future<void> _loadCartFromRemote() async {
    try {
      final box = Hive.box(Constants.authStorageKey);
      final token = box.get('token');
      final url = Uri.parse('http://192.168.1.9:5000/api/v1/products/getcartItems');
      final headers = {"Authorization": "Bearer $token"};
      final response = await http.get(url, headers: headers);

      if (response.statusCode == 200) {
        final jsonData = json.decode(response.body)['product'];
        Map<String, CartItem> fetchedCart = {};

        for (var productData in jsonData) {
          CartItem product = CartItem.fromJson(productData);
          // 给qty设置默认值1(接口返回无此字段时)
          product.qty = product.qty ?? 1;
          fetchedCart[product.productId!] = product;
        }

        // 替换整个state对象完成状态更新
        state = fetchedCart;
      }
    } catch (e) {
      print(e);
      // 可选:请求失败时加载本地缓存数据
    }
  }

  // 添加商品到购物车(含数量递增逻辑)
  void addItem({required String productId, required price, required itemsName, required itemsImage}) {
    if (state.containsKey(productId)) {
      state = {
        ...state,
        productId: CartItem(
          productId: state[productId]!.productId,
          itemsName: state[productId]!.itemsName,
          price: state[productId]!.price,
          itemsImage: state[productId]!.itemsImage,
          qty: state[productId]!.qty! + 1,
        ),
      };
    } else {
      state = {
        ...state,
        productId: CartItem(
          productId: productId,
          itemsName: itemsName,
          price: price,
          itemsImage: itemsImage,
          qty: 1,
        ),
      };
    }
    // Riverpod会自动监听state变化并通知UI,无需手动调用notifyListeners
  }

  // 可选:添加商品数量递减/删除商品方法
  void decreaseQty(String productId) {
    if (state.containsKey(productId) && state[productId]!.qty! > 1) {
      state = {
        ...state,
        productId: CartItem(
          productId: state[productId]!.productId,
          itemsName: state[productId]!.itemsName,
          price: state[productId]!.price,
          itemsImage: state[productId]!.itemsImage,
          qty: state[productId]!.qty! - 1,
        ),
      };
    } else {
      removeItem(productId);
    }
  }

  void removeItem(String productId) {
    if (state.containsKey(productId)) {
      state = Map.from(state)..remove(productId);
    }
  }
}

final cartRepositoryProvider = NotifierProvider<CartRepository, Map<String, CartItem>>(CartRepository.new);
修复后的CartItem模型
class CartItem {
  String? productId;
  String? itemsName;
  String? price;
  String? itemsImage;
  int? qty;

  CartItem({
    required this.productId,
    required this.itemsName,
    required this.price,
    required this.itemsImage,
    required this.qty,
  });

  CartItem.fromJson(Map<String, dynamic> json) {
    productId = json['itemsId'];
    itemsName = json['itemsName'];
    itemsImage = json['itemsImage'];
    price = json['itemsPrice'];
    // 兼容接口返回的qty字段(如果存在)
    qty = json['qty'];
  }
}

3. 关键说明

  • 自动初始化:build方法在Provider首次被监听时执行,应用重启后会重新触发,因此_loadCartFromRemote会自动执行,实现重启后重新获取数据。
  • 状态更新规范:Riverpod的Notifier必须通过创建新的state对象来更新状态,不能直接修改原state的内容,所以使用state = {...state, ...}的方式生成新Map。
  • 错误处理:请求失败时可扩展逻辑,比如加载Hive本地缓存的购物车数据,提升用户体验。

内容的提问来源于stack exchange,提问作者Mohammed M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 02:37:49