I'm currently learning Riverpod and I'm trying to implementing Riverpod inside my BottomSheetModal. Which will triggered based on QRcode Scanner. Then upon scanned, i want it to retrieve the data from Firestore and present it to user inside the modal.
part of Scanned_Shipment_Modal.dart
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(50)),
isScrollControlled: true,
builder: (context) {
return FutureBuilder(
future: Future.value(capture),
builder: (context, snapshot) {
if (snapshot.hasData) {
var dateNow = DateTime.now();
var shipmentoutdataref = ref.watch(getShipmentOutDataProvider(
shipmentTrack: barcode.barcodes.first.rawValue!,
dateNow: dateNow,
));
return shipmentoutdataref.when(
data: (data) {
debugPrint(data.toString());
return Wrap(
children: [
ScannedShipmentOutModal(shipmentoutdataref: data)
],
);
},
error: (error, stackTrace) => ErrorPopup().errorPopup(
context, "Error", "No Da"),
loading: () {
return const LoadingCircle(
height: 200,
width: 200,
);
});
} else {
return ErrorPopup()
.errorPopup(context, "Error", "No Data Avaliable");
}
});
});
However, My AsyncValue.when
object keep returning as endless state of loading instead of returning data. I'm pretty sure i'm doing something wrong in regard of the provider code part, but after hours of searching google and debugging. i couldn't determined the reason as to why it won't load. So i could use some fresh eyes here.
scanned_shipment_out_provider.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:intl/intl.dart';
import 'package:logistec/models/Firebase/model/firestore_data_models.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'scanned_shipment_out_provider.g.dart';
@riverpod
Future<FirestoreShipmentOutData?> getShipmentOutData(GetShipmentOutDataRef ref,
{required String shipmentTrack, required DateTime dateNow}) async {
FirebaseFirestore firestore = FirebaseFirestore.instance;
String getformattedDate = DateFormat("dd-MM-yy").format(dateNow);
var dataref =
firestore.collection("DHL_Service_RecheckData").doc(getformattedDate);
var data = await dataref.get();
try {
var dataList = data.get(shipmentTrack);
return FirestoreShipmentOutData.fromJSON(dataList);
} catch (e) {
return null;
}
}
I knew that FutureBuilder widget will work just fine in this case. but i really want to understand Riverpod and thus, attempted to use it as much as i can. Plus it seems more readable for me. And so i'd appreciated the explanation of what i did wrong and how to corrected it. Thank you!
(Not sure it's related since according to many threads, they are there just to support the main files. but just in case, here's generated code from build_runner)
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'scanned_shipment_out_provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$getShipmentOutDataHash() =>
r'63e7aae52cf51686a22aad856f1c414e4ec35a2f';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
typedef GetShipmentOutDataRef
= AutoDisposeFutureProviderRef<FirestoreShipmentOutData?>;
/// See also [getShipmentOutData].
@ProviderFor(getShipmentOutData)
const getShipmentOutDataProvider = GetShipmentOutDataFamily();
/// See also [getShipmentOutData].
class GetShipmentOutDataFamily
extends Family<AsyncValue<FirestoreShipmentOutData?>> {
/// See also [getShipmentOutData].
const GetShipmentOutDataFamily();
/// See also [getShipmentOutData].
GetShipmentOutDataProvider call({
required String shipmentTrack,
required DateTime dateNow,
}) {
return GetShipmentOutDataProvider(
shipmentTrack: shipmentTrack,
dateNow: dateNow,
);
}
@override
GetShipmentOutDataProvider getProviderOverride(
covariant GetShipmentOutDataProvider provider,
) {
return call(
shipmentTrack: provider.shipmentTrack,
dateNow: provider.dateNow,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'getShipmentOutDataProvider';
}
/// See also [getShipmentOutData].
class GetShipmentOutDataProvider
extends AutoDisposeFutureProvider<FirestoreShipmentOutData?> {
/// See also [getShipmentOutData].
GetShipmentOutDataProvider({
required this.shipmentTrack,
required this.dateNow,
}) : super.internal(
(ref) => getShipmentOutData(
ref,
shipmentTrack: shipmentTrack,
dateNow: dateNow,
),
from: getShipmentOutDataProvider,
name: r'getShipmentOutDataProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$getShipmentOutDataHash,
dependencies: GetShipmentOutDataFamily._dependencies,
allTransitiveDependencies:
GetShipmentOutDataFamily._allTransitiveDependencies,
);
final String shipmentTrack;
final DateTime dateNow;
@override
bool operator ==(Object other) {
return other is GetShipmentOutDataProvider &&
other.shipmentTrack == shipmentTrack &&
other.dateNow == dateNow;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, shipmentTrack.hashCode);
hash = _SystemHash.combine(hash, dateNow.hashCode);
return _SystemHash.finish(hash);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
I'm not quite an expert on Riverpod, but I would say that whenever your
var shipmentoutdataref = ref.watch(getShipmentOutDataProvider(
shipmentTrack: barcode.barcodes.first.rawValue!,
dateNow: dateNow,
));
receives data, the builder is called again to build the loaded data. However, in this case your shipmentoutdataref
changes in the process, as dateNow will be different and thus you end up with a different provider (i.e. your shipmentoutdataref is no longer the same.). This new provider will be in the loading state, and once it has received data, the same sequence occurs. You might be able to fix this by moving the dateNow to somewhere within the providers as opposed to the 'initializer', if possible.