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

Flutter Riverpod购物车异常:数量不实时更新、商品无法添加

问题排查与修复方案

核心问题分析

你的购物车功能出现两个问题的根本原因在于StateNotifier状态更新机制错误和商品对象判断逻辑失效:

  1. 自定义的_carts列表未与StateNotifier的state绑定,修改后未触发UI刷新
  2. 直接修改product.qty但未通知StateNotifier更新状态,导致UI无法实时感知变化
  3. contains(product)默认判断对象引用而非商品ID,导致重复添加或数量更新失效
  4. ProductModel.fromJson中qty的赋值错误(json[1]应为json['qty'])

逐步修复代码

1. 修复ProductModel类

重写==和hashCode,基于商品ID判断是否为同一商品;修正fromJson的qty赋值:

class ProductModel {
  int? id;
  int qty = 1;
  String? product_name;
  String? product_description;
  int? product_price;
  String? images;

  ProductModel({this.id, required this.qty, this.product_name, this.product_description, this.product_price, this.images});

  ProductModel.fromJson(Map<String, dynamic> json) {
    id = int.tryParse(json['id']);
    product_name = json['product_name'];
    product_description = json['product_description'];
    product_price = int.tryParse(json['product_price']);
    images = json['images'];
    qty = json['qty'] ?? 1; // 修正为json['qty']而非json[1]
  }

  // 重写==和hashCode,基于id判断是否为同一商品
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is ProductModel &&
          runtimeType == other.runtimeType &&
          id == other.id;

  @override
  int get hashCode => id.hashCode;
}

2. 修复Productstore类

移除自定义_carts列表,直接使用StateNotifier的state;所有修改操作后必须更新state以触发UI刷新:

import 'package:five_star/ProductModel.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class Productstore extends StateNotifier<List<ProductModel>>{
  Productstore(): super([]);

  void addToCart(ProductModel product) {
    // 查找是否已存在同ID商品
    final existingProduct = state.firstWhere(
      (p) => p.id == product.id,
      orElse: () => ProductModel(id: -1, qty: 0), // 占位无效商品
    );

    if (existingProduct.id != -1) {
      // 已存在则更新数量
      final updatedList = state.map((p) {
        if (p.id == product.id) {
          return ProductModel(
            id: p.id,
            qty: p.qty + 1,
            product_name: p.product_name,
            product_description: p.product_description,
            product_price: p.product_price,
            images: p.images,
          );
        }
        return p;
      }).toList();
      state = updatedList;
    } else {
      // 不存在则添加新商品
      state = [...state, product];
    }
  }

  void removeFromCart(ProductModel product) {
    state = state.where((p) => p.id != product.id).toList();
  }

  void removeCartqty(ProductModel product) {
    final updatedList = state.map((p) {
      if (p.id == product.id) {
        if (p.qty == 1) {
          // 数量为1时移除商品
          return null;
        } else {
          // 数量减1
          return ProductModel(
            id: p.id,
            qty: p.qty - 1,
            product_name: p.product_name,
            product_description: p.product_description,
            product_price: p.product_price,
            images: p.images,
          );
        }
      }
      return p;
    }).whereType<ProductModel>().toList();
    state = updatedList;
  }

  void addCartqty(ProductModel product) {
    final updatedList = state.map((p) {
      if (p.id == product.id) {
        return ProductModel(
          id: p.id,
          qty: p.qty + 1,
          product_name: p.product_name,
          product_description: p.product_description,
          product_price: p.product_price,
          images: p.images,
        );
      }
      return p;
    }).toList();
    state = updatedList;
  }
}

3. 修复product_detail页面

移除重复的ref.read,确保UI能监听state变化;从state中获取当前商品的最新数量:

import 'package:five_star/Cart.dart';
import 'package:five_star/ProductModel.dart';
import 'package:five_star/ProductStore.dart';
import 'package:five_star/all_products.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:five_star/home.dart';

final cartprovider = StateNotifierProvider<Productstore, List<ProductModel>>((ref) => Productstore());

class product_detail extends ConsumerStatefulWidget {
  const product_detail({super.key});

  @override
  product_detailState createState() => product_detailState();
}

class product_detailState extends ConsumerState<product_detail> {
  @override
  Widget build(BuildContext context) {
    final productArg = ModalRoute.of(context)!.settings.arguments as ProductModel;
    // 监听购物车状态,获取当前商品的最新信息
    final cartItems = ref.watch(cartprovider);
    final currentProduct = cartItems.firstWhere(
      (p) => p.id == productArg.id,
      orElse: () => productArg, // 如果未加入购物车,使用原始商品
    );
    final cartNotifier = ref.read(cartprovider.notifier);

    return Scaffold(
      appBar: AppBar(
        title: const Text('PRODUCT DETAIL'),
        backgroundColor: Colors.orange,
      ),
      body: ListView(
        children: [
          Container(
            height: MediaQuery.of(context).size.height,
            color: Colors.white,
            child: Column(
              children: [
                Padding(
                  padding: const EdgeInsets.all(10.0),
                  child: Container(
                    height: 160,
                    width: double.infinity,
                    child: Card(
                      color: Colors.white,
                      child: Image.network("https://hometronix.co.tz/admin/images/products/${productArg.images}"),
                    ),
                  ),
                ),
                Center(
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Text(
                      productArg.product_name ?? '',
                      style: const TextStyle(
                          color: Colors.black,
                          fontSize: 20,
                          fontWeight: FontWeight.bold),
                    ),
                  ),
                ),
                Center(
                  child: Padding(
                    padding: const EdgeInsets.all(4.0),
                    child: Text(
                      "${productArg.product_price ?? 0}",
                      style: const TextStyle(color: Colors.black, fontSize: 20),
                    ),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(10.0),
                  child: Container(
                    height: 200,
                    width: MediaQuery.of(context).size.width,
                    child: Center(
                        child: Text(productArg.product_description ?? '')),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: SizedBox(
                    height: 50,
                    width: MediaQuery.of(context).size.width / 2,
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        IconButton(
                            onPressed: () {
                              cartNotifier.removeCartqty(productArg);
                            },
                            icon: const Icon(
                              Icons.remove,
                              color: Colors.red,
                            )),
                        Text(
                          "${currentProduct.qty}",
                          style: const TextStyle(color: Colors.black),
                        ),
                        IconButton(
                            onPressed: () {
                              cartNotifier.addCartqty(productArg);
                            },
                            icon: const Icon(
                              Icons.add,
                              color: Colors.green,
                            )),
                      ],
                    ),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: SizedBox(
                    height: 50,
                    width: MediaQuery.of(context).size.width / 2,
                    child: ElevatedButton(
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.orange,
                        foregroundColor: Colors.black,
                      ),
                      onPressed: () {
                        cartNotifier.addToCart(productArg);
                      },
                      child: const Text(
                        'add to cart',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ),
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}

修复说明

  1. StateNotifier状态更新:所有购物车操作后都通过生成新列表的方式更新state,确保Riverpod能通知UI刷新
  2. 商品唯一性判断:通过重写==和hashCode,基于商品ID判断是否为同一商品,解决contains判断失效问题
  3. 不可变对象更新:修改商品数量时生成新的ProductModel对象,符合Riverpod的不可变状态管理原则
  4. UI数据同步:从ref.watch(cartprovider)中获取最新的商品数量,确保UI展示的是购物车中的实时数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 20:27:06