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

Flutter 基于Provider与Cloud Firestore的商品收藏系统功能异常求助

问题根因

你遇到的问题来自两个核心逻辑错误:

  1. 异步方法未等待就取值:checkFavorite是异步网络请求方法,你在build方法中直接调用后立即打印isLiked,此时Firestore查询还未返回结果,拿到的永远是修改前的旧值。首次进入页面时_isLiked默认值为false,所以首次打印结果永远是false,等请求完成修改_isLiked触发重绘后,状态才会更新。
  2. 全局状态未重置导致残留:ProductService是全局单例,你用同一个_isLiked变量存储所有商品的收藏状态,进入新的商品详情页时没有先重置这个值,上一个商品的收藏状态会一直残留,直到新的checkFavorite请求完成才会覆盖,就会出现不同商品状态串改的问题。

修复方案

1. 优化ProductService状态逻辑

优先改用Map存储不同商品的收藏状态,避免单值复用导致的状态串改,同时请求前先初始化状态:

class ProductService extends ChangeNotifier {
  // 用Map存储不同商品ID对应的收藏状态,避免单值残留
  final Map<String, bool> _favoriteStatusMap = {};

  // 传入商品ID获取对应收藏状态
  bool isLiked(String productId) => _favoriteStatusMap[productId] ?? false;

  Future<bool> checkFavorite(String? uid, String? productId) async {
    if (uid == null || productId == null) {
      _favoriteStatusMap[productId ?? ''] = false;
      notifyListeners();
      return false;
    }
    // 可自行加缓存逻辑,不需要重复查询直接返回已有结果
    if (_favoriteStatusMap.containsKey(productId)) {
      return _favoriteStatusMap[productId]!;
    }
    final resp = await _firestore.collection('users').doc(uid).get();
    Map<String, dynamic> data = resp.data() as Map<String, dynamic>;
    var likedProducts = data['liked_products'] as List<dynamic>;
    final currentStatus = likedProducts.contains(productId);
    _favoriteStatusMap[productId] = currentStatus;
    notifyListeners();
    return currentStatus;
  }

  // 切换收藏状态时也要同步更新Map
  Future<void> toggleFavorite(String uid, String productId) async {
    // 原有切换收藏的Firestore操作逻辑
    final newStatus = !isLiked(productId);
    _favoriteStatusMap[productId] = newStatus;
    notifyListeners();
  }
}

2. 页面异步逻辑处理

将ProductScreen改为StatefulWidget,在初始化阶段触发异步查询,使用FutureBuilder处理加载状态,避免在build中直接调用异步方法:

class ProductScreen extends StatefulWidget {
  const ProductScreen({Key? key}) : super(key: key);

  @override
  State<ProductScreen> createState() => _ProductScreenState();
}

class _ProductScreenState extends State<ProductScreen> {
  late Future<bool> _favoriteCheckFuture;
  late Product currentProduct;
  late UserModel loggedInUser;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    final productService = Provider.of<ProductService>(context, listen: false);
    final arguments = ModalRoute.of(context)!.settings.arguments as Map;
    currentProduct = arguments["product"] as Product;
    loggedInUser = arguments['user'] as UserModel;
    productService.getProductSeller(currentProduct.productSeller);
    // 初始化异步查询任务
    _favoriteCheckFuture = productService.checkFavorite(loggedInUser.uid, currentProduct.productId);
  }

  @override
  Widget build(BuildContext context) {
    final productService = Provider.of<ProductService>(context);
    return FutureBuilder<bool>(
      future: _favoriteCheckFuture,
      builder: (context, snapshot) {
        // 加载中状态展示
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Scaffold(
            body: const Center(child: CircularProgressIndicator()),
          );
        }
        // 拿到结果后渲染页面
        final isLiked = productService.isLiked(currentProduct.productId);
        return Scaffold(
          // 你的原有页面布局,用isLiked渲染收藏按钮状态
        );
      },
    );
  }
}

如果你不想修改为Map存储,也可以保留单_isLiked变量,只需要在每次调用checkFavorite前先把_isLiked重置为false并调用notifyListeners()即可解决状态残留问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 14:06:03