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

Flutter电商应用购物车计数器切换页面重置,如何实现数据持久化

解决方案

问题根因

你当前的计数器数值numOfItems是存储在CartCounter组件的本地State中的,当页面切换、组件销毁重建时,本地State会被重置,所以计数器会归零。而且你已经引入了Cart Provider做全局购物车管理,完全不需要在组件本地单独维护计数,直接从全局购物车读取对应商品的数量即可。

最优实现方案

你已经在使用Provider做状态管理,最优方案就是把计数器数据的来源绑定到全局Cart Provider,再给Cart加本地持久化存储,既不需要引入额外的状态管理库,也能保证APP重启后数据也不会丢失。

步骤1:改造CartCounter组件

移除本地维护的numOfItems状态,直接从Cart Provider中读取当前商品的购买数量,同时接收上层传递的product参数:

// cart_counter.dart
import 'package:flutter/material.dart';
import '../providers/cart.dart';
import 'package:provider/provider.dart';
import '../providers/products.dart';

class CartCounter extends StatefulWidget {
  // 新增接收当前商品参数
  final Product product;
  const CartCounter({Key? key, required this.product}) : super(key: key);

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

class _CartCounterState extends State<CartCounter> {
  // 移除本地的numOfItems变量
  @override
  Widget build(BuildContext context) {
    // 这里listen设为true,购物车变化时自动刷新计数器
    final cart = Provider.of<Cart>(context, listen: true);
    // 从购物车中获取当前商品的数量,不存在则返回0
    int numOfItems = cart.items[widget.product.id]?.quantity ?? 0;
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        CounterButton(
          icon: Icons.remove,
          onPress: () {
            if (numOfItems > 0) {
              cart.removeSingleItem(widget.product.id);
            }
          },
        ),
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: 13.0),
          child: Text(
            numOfItems.toString(),
            style: const TextStyle(
              fontSize: 20.0,
            ),
          ),
        ),
        CounterButton(
          icon: Icons.add,
          onPress: () {
            cart.addItem(
              widget.product.id,
              widget.product.price,
              widget.product.title,
            );
          },
        ),
      ],
    );
  }
}

// CounterButton部分代码无修改,此处省略

步骤2:修改ProductItem传递product参数

你之前直接引用const CartCounter()没有传递当前商品数据,需要修改为传递当前产品:

// product_item.dart 对应位置修改
// 替换原来的 const CartCounter()
CartCounter(product: Product(id, title, price, image)),

步骤3:给Cart Provider加本地持久化

推荐用Hive做本地存储,性能高、使用简单,不需要额外做JSON序列化:

  1. 先在pubspec.yaml引入hive和hive_flutter依赖
  2. 改造Cart类,在添加/删除商品的时候自动同步到本地Hive存储,APP启动时从Hive读取数据初始化购物车:
    示例Cart类实现:
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import '../models/cart_item.dart';

class Cart with ChangeNotifier {
  Map<String, CartItem> _items = {};
  final Box _cartBox = Hive.box('cart');

  Cart() {
    // 初始化时从本地读取购物车数据
    var savedItems = _cartBox.get('items');
    if (savedItems != null) {
      _items = Map<String, CartItem>.from(savedItems);
    }
  }

  Map<String, CartItem> get items => {..._items};

  void addItem(String productId, double price, String title) {
    if (_items.containsKey(productId)) {
      _items.update(productId, (existing) => CartItem(
        id: existing.id,
        title: existing.title,
        price: existing.price,
        quantity: existing.quantity + 1,
      ));
    } else {
      _items.putIfAbsent(productId, () => CartItem(
        id: DateTime.now().toString(),
        title: title,
        price: price,
        quantity: 1,
      ));
    }
    // 同步到本地存储
    _cartBox.put('items', _items);
    notifyListeners();
  }

  void removeSingleItem(String productId) {
    if (!_items.containsKey(productId)) return;
    if (_items[productId]!.quantity > 1) {
      _items.update(productId, (existing) => CartItem(
        id: existing.id,
        title: existing.title,
        price: existing.price,
        quantity: existing.quantity - 1,
      ));
    } else {
      _items.remove(productId);
    }
    // 同步到本地存储
    _cartBox.put('items', _items);
    notifyListeners();
  }
}

改造完成后,不管是切换页面还是重启APP,计数器的数值都不会丢失,完全和全局购物车数据同步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 10:15:08