Search code examples
flutterdartgoogle-cloud-firestoreprovider

Flutter, Cloud Firestore and Provider : Fetching data


I have products stored on cloud firestore, I am able to fetch and display the products using the provider package. However, when I go to different page and return to the products screen, the products are duplicated every time.

products class

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';

class Product with ChangeNotifier {
  final String id;
  final String title;
  final double price;
  final String imageUrl;

  Product({
    required this.id,
    required this.title,
    required this.price,
    required this.imageUrl,
  });
}

class Products with ChangeNotifier {
  final List<Product> _products = [];

  Future<void> fetchProducts() async {
    await FirebaseFirestore.instance
        .collection('products')
        .orderBy('id', descending: true)
        .get()
        .then((QuerySnapshot snapshot) {
      for (var doc in snapshot.docs) {
        _products.insert(
            0,
            Product(
              id: doc['id'],
              title: doc['title'],
              price: doc['price'],
              imageUrl: doc['imageUrl'],
            ));
        notifyListeners();
      }
    });
  }

  List<Product> get items {
    return [..._products];
  }
}

products screen

import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import '/constants/constants.dart';
import 'package:provider/provider.dart';
import '/providers/products.dart';
import '/widgets/product_list.dart';

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

  @override
  State<ProductsScreen> createState() => _ProductsScreenState();
}

class _ProductsScreenState extends State<ProductsScreen> {
  var _isInit = true;
  var _isLoading = false;
  @override
  void didChangeDependencies() {
    if (_isInit) {
      setState(() {
        _isLoading = true;
      });
      Provider.of<Products>(context).fetchProducts().then((_) {
        setState(() {
          _isLoading = false;
        });
      });
    }
    _isInit = false;
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _isLoading
          ? const Center(
              child: SpinKitThreeBounce(
                color: kPrimaryColor,
                size: 30.0,
              ),
            )
          : const ProductList(),
    );
  }
}


Solution

  • You can simply add constructer inside the provider and initialize the _products list, or just clear the _products just right before the for loop

       class Products{
      List<dynamic> _products;
      Producst(){
        _products=[];
      }
    }
    

    or

    class Products{
      List<dynamic> _products;
     void fetch(){
       _products.clear();
     }
    }