Jamal Ahmad
Jamal Ahmad

Reputation: 99

Flutter Riverpod context.read(providerref) doesn't give same reference of stateNotifier when call in two different functions of a Widget

I am setting values of variables declared in View Model class which is a StateNotifier, inside a function of widget. When I try to access the values of those variables from a different function of same widget, their values are null. I have debugged code to verify that first function is setting values correctly.

Any help will be highly appreciated.

Here is cutdown version of my StateNotifier

class ProductViewModel extends StateNotifier<ProductState> {
  String errorMessage;

  Product product;

  final ProductService productService;
  final CategoryService categoryService;
  final BrandService brandService;
  final TranslatorService translatorService;
  final ProductOptionsViewModel productOptionsViewModel;
  final ProductVariantViewModel productVariantViewModel;

  ProductViewModel(this.productService, this.categoryService, this.brandService, this.translatorService,
      this.productOptionsViewModel, this.productVariantViewModel)
      : super(ProductInitial());

  String productId;
  List<SizeEnum> _sizes;
  String _selectedBrand;
  String _selectedCategory;
  String _selectedStore;
  String _productName;
  String _productIntlName;
  String _sku;

  String get selectedBrand => _selectedBrand;

  set selectedBrand(String value) {
    _selectedBrand = value;
  }  

  String get selectedCategory => _selectedCategory;

  set selectedCategory(String value) {
    _selectedCategory = value;
  }

  String get selectedStore => _selectedStore;

  set selectedStore(String value) {
    _selectedStore = value;
  }

  String get productName => _productName;

  set productName(String value) {
    _productName = value;
  }

  String get productIntlName => _productIntlName;

  set productIntlName(String value) {
    _productIntlName = value;
  }

  String get sku => _sku;

  set sku(String value) {
    _sku = value;
  }

  Future<bool> saveProductDetails() async {
    bool isSave = false;
    bool imageSaved = await saveProductImage();
    if (!imageSaved) return imageSaved;
    List<String> searchKeywords = indexProductName(_productName);
    List<String> searchTag1 = _searchTag1 != null ? indexProductName(_searchTag1) : null;
    List<String> searchTag2 = _searchTag2 != null ? indexProductName(_searchTag2) : null;
    List<String> searchTag3 = _searchTag3 != null ? indexProductName(_searchTag3) : null;
    if (deal != null && _dealsAddedDateTime == null) {
      _dealsAddedDateTime = DateTime.now();
    }
    print(productOptionsViewModel.toString());


    Product _product = Product(
        productId: productId,
        name: _productName,
        intlName: _productIntlName,
        category: FirebaseFirestore.instance.doc(_selectedCategory),
        brand: FirebaseFirestore.instance.doc(_selectedBrand),
        sku: _sku,
        quantity: _quantity,
        price: _price,
        containSizes: productOptionsViewModel.sizes,
        containColors: productOptionsViewModel.colors,
        accessory: productOptionsViewModel.accessory ,
        salesTaxApplicable: productOptionsViewModel.salesTax,
    );

    isSave = await productService.saveProduct(_product);
    if (!isSave) {
      errorMessage = "Error in saving product information";
    } else {
      productId = productService.newProductId;
    }
   
    return isSave;
  } 
}

StateNotifierProvider declaration

final productViewModelProvider = StateNotifierProvider.autoDispose<ProductViewModel,ProductState>((ref) => ProductViewModel(
    ref.watch(productServiceProvider),
    ref.watch(categoryServiceProvider),
    ref.watch(brandServiceProvider),
    ref.watch(translatorServiceProvider),
    ref.watch(productOptionsViewModelProvider),
    ref.watch(productVariantViewModelProvider)));

UI Functions I set values in validateProduct and read values again in saveProductDetails.

  Future<bool> validateProduct() async {
    if (_formKey.currentState.validate()) {
      _formKey.currentState.save();
      final model = context.read(productViewModelProvider.notifier);
      final storeViewModel = context.read(storeViewModelProvider.notifier);
      var _store = await storeViewModel.getMyStore();
      model.productName = _productName;
      model.productIntlName = _productIntlName;
      model.sku = _sku;
      model.quantity = _quantity;
      model.price = _price;
      model.selectedBrand = _selectedBrand;
      model.selectedCategory = _selectedCategory;
      model.selectedStore = _storeCode;
      model.description = _productDescription;
      model.manufacturerLink = _manufacturerLink;
      model.searchTag1 = _searchTag1;
      model.searchTag2 = _searchTag2;
      model.searchTag3 = _searchTag3;
      if (model.addedDateTime == null) {
        model.addedDateTime = DateTime.now();
      }
      if (_storeCode == null) {
        _storeCode = _store.store;
      }
      if (model.selectedStore == null) {
        model.selectedStore = _storeCode;
      }
      return true;
    }
    else return false;
  }


 Future<bool> saveProductDetails() async {
    final model = context.read(productViewModelProvider.notifier);

    bool isProductSaved = await model.saveProductDetails();
    if (isProductSaved) {
      if (_isProductExist) {
        displayMessage(context, "Product Information Updated");
      } else
        displayMessage(context, "Product Information Saved");

      _formSaved = true;
      isFormChanged = false;
      return true;
    } else if (isProductSaved == false) {
      _formSaved = false;
      displayMessage(context, model.errorMessage);
    }

    return isProductSaved;
  }

State

abstract class ProductState {
  const ProductState();
}

class ProductInitial extends ProductState {
  const ProductInitial();
}

class ProductLoading extends ProductState {
  const ProductLoading();
}

class ProductLoaded extends ProductState {
  final Product product;

  ProductLoaded(this.product);

  @override
  bool operator ==(Object other) =>
      identical(this, other) || other is ProductLoaded && runtimeType == other.runtimeType && product == other.product;

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

class ProductSaving extends ProductState {
  const ProductSaving();
}

class ProductSaved extends ProductState {
  final Product product;

  ProductSaved(this.product);

  @override
  bool operator ==(Object other) =>
      identical(this, other) || other is ProductSaved && runtimeType == other.runtimeType && product == other.product;

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

class ProductError extends ProductState {
  final String errorMessage;

  ProductError(this.errorMessage);
}

Upvotes: 1

Views: 1056

Answers (1)

Shahzaib Ahmed
Shahzaib Ahmed

Reputation: 329

Remove .autoDispose modifier

final productViewModelProvider = StateNotifierProvider<ProductViewModel,ProductState>((ref) => ProductViewModel(
ref.watch(productServiceProvider),
ref.watch(categoryServiceProvider),
ref.watch(brandServiceProvider),
ref.watch(translatorServiceProvider),
ref.watch(productOptionsViewModelProvider),
ref.watch(productVariantViewModelProvider)));

Upvotes: 2

Related Questions