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

Flutter Web页面刷新时如何高效保留购物车等状态数据?

Flutter Web 购物车状态持久化方案推荐(结合Riverpod)

针对页面刷新后Riverpod管理的购物车状态丢失问题,结合电商场景分析几种方案的优劣,并给出具体实现思路:

方案对比与选型建议

1. Shared Preferences

  • 适用场景:购物车数据结构简单(仅含商品ID、数量等基础字段)、数据量不大的情况。
  • 优势:Flutter官方维护,API简单,Web端底层基于localStorage实现,上手成本极低。
  • 劣势:仅支持存储基本数据类型,复杂对象需手动做JSON序列化/反序列化。

2. Hive

  • 适用场景:购物车包含多字段复杂商品对象(如名称、价格、图片地址等),需要更高效的序列化方式。
  • 优势:轻量级NoSQL数据库,支持自定义对象直接存储(无需JSON转换),性能优于Shared Preferences,Web端可配置存储到IndexedDB(容量更大)。
  • 劣势:需要为自定义类编写Adapter,比Shared Preferences多一点配置成本。

3. Cookies

  • 适用场景:购物车数据需要和后端会话同步(如未登录用户的临时购物车需在多设备/会话间同步),或依赖后端鉴权逻辑。
  • 优势:可设置过期时间,天然支持跨会话保持,能和后端交互。
  • 劣势:容量限制4KB左右,每次HTTP请求都会携带,纯前端存储场景下没必要增加额外开销。

最终推荐

  • 纯前端临时存储(未登录用户):
    • 数据简单 → 选Shared Preferences
    • 数据复杂 → 选Hive
  • 需后端同步(已登录用户):优先将购物车数据存储到后端数据库,前端仅存用户标识,刷新后从后端拉取完整购物车数据。

结合Riverpod的实现示例

示例1:Shared Preferences + Riverpod StateNotifier

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';

final cartProvider = StateNotifierProvider<CartNotifier, List<CartItem>>((ref) {
  return CartNotifier();
});

class CartNotifier extends StateNotifier<List<CartItem>> {
  CartNotifier() : super([]) {
    _loadSavedCart();
  }

  // 从SharedPreferences加载购物车数据
  Future<void> _loadSavedCart() async {
    final prefs = await SharedPreferences.getInstance();
    final cartJson = prefs.getString('user_cart');
    if (cartJson != null) {
      final List<dynamic> cartData = jsonDecode(cartJson);
      state = cartData.map((item) => CartItem.fromJson(item)).toList();
    }
  }

  // 添加商品到购物车并持久化
  Future<void> addToCart(CartItem item) async {
    state = [...state, item];
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(
      'user_cart',
      jsonEncode(state.map((cartItem) => cartItem.toJson()).toList()),
    );
  }

  // 清空购物车并同步删除存储
  Future<void> clearCart() async {
    state = [];
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove('user_cart');
  }
}

// 购物车商品模型
class CartItem {
  final String productId;
  final String productName;
  final int quantity;
  final double price;

  CartItem({
    required this.productId,
    required this.productName,
    required this.quantity,
    required this.price,
  });

  // 序列化
  Map<String, dynamic> toJson() => {
        'productId': productId,
        'productName': productName,
        'quantity': quantity,
        'price': price,
      };

  // 反序列化
  factory CartItem.fromJson(Map<String, dynamic> json) => CartItem(
        productId: json['productId'],
        productName: json['productName'],
        quantity: json['quantity'],
        price: json['price'].toDouble(),
      );
}

示例2:Hive + Riverpod StateNotifier

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';

// 初始化Hive(在main函数中调用)
// void main() async {
//   await Hive.initFlutter();
//   Hive.registerAdapter(CartItemAdapter());
//   await Hive.openBox<CartItem>('cart_box');
//   runApp(const ProviderScope(child: MyApp()));
// }

final cartProvider = StateNotifierProvider<CartNotifier, List<CartItem>>((ref) {
  return CartNotifier();
});

class CartNotifier extends StateNotifier<List<CartItem>> {
  final Box<CartItem> _cartBox = Hive.box<CartItem>('cart_box');

  CartNotifier() : super([]) {
    _loadSavedCart();
  }

  // 从Hive加载购物车数据
  void _loadSavedCart() {
    state = _cartBox.values.toList();
  }

  // 添加商品到购物车并持久化
  void addToCart(CartItem item) {
    state = [...state, item];
    _cartBox.add(item);
  }

  // 清空购物车
  void clearCart() {
    state = [];
    _cartBox.clear();
  }
}

// Hive购物车商品模型(带Adapter)
@HiveType(typeId: 0)
class CartItem {
  @HiveField(0)
  final String productId;
  @HiveField(1)
  final String productName;
  @HiveField(2)
  final int quantity;
  @HiveField(3)
  final double price;

  CartItem({
    required this.productId,
    required this.productName,
    required this.quantity,
    required this.price,
  });
}

// Hive自定义对象Adapter
class CartItemAdapter extends TypeAdapter<CartItem> {
  @override
  final int typeId = 0;

  @override
  CartItem read(BinaryReader reader) {
    return CartItem(
      productId: reader.readString(),
      productName: reader.readString(),
      quantity: reader.readInt(),
      price: reader.readDouble(),
    );
  }

  @override
  void write(BinaryWriter writer, CartItem obj) {
    writer.writeString(obj.productId);
    writer.writeString(obj.productName);
    writer.writeInt(obj.quantity);
    writer.writeDouble(obj.price);
  }
}

注意事项

  • 持久化时机:状态变更时立即写入存储避免数据丢失;若频繁操作,可考虑防抖批量写入平衡性能与安全性。
  • 数据同步:用户登录后,建议将前端临时购物车数据同步到后端,再清空前端存储,保证数据一致性。
  • 容量限制:localStorage容量约5MB,IndexedDB容量更大,Hive可通过Hive.initFlutter('path')配置存储位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 09:21:01