В настоящее время я изучаю Riverpod и пытаюсь внедрить Riverpod в свой BottomSheetModal. Который будет запущен на основе сканера QRcode. Затем после сканирования я хочу, чтобы он извлек данные из Firestore и представил их пользователю внутри модального окна.
часть 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");
}
});
});
Однако объект My AsyncValue.when продолжает возвращаться в виде бесконечного состояния загрузки вместо возврата данных. Я почти уверен, что делаю что-то не так в отношении части кода провайдера, но после нескольких часов поиска в Google и отладки. Я не мог определить причину, по которой он не загружается. Так что я мог бы использовать некоторые свежие глаза здесь.
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;
}
}
Я знал, что в этом случае виджет FutureBuilder отлично сработает. но я действительно хочу понять Riverpod и поэтому пытался использовать его как можно больше. Кроме того, он кажется более читабельным для меня. И поэтому я оценил объяснение того, что я сделал неправильно и как это исправить. Спасибо!
(Не уверен, что это связано, поскольку, согласно многим потокам, они нужны только для поддержки основных файлов. Но на всякий случай вот сгенерированный код из 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





Я не совсем эксперт по Riverpod, но я бы сказал, что всякий раз, когда вы
var shipmentoutdataref = ref.watch(getShipmentOutDataProvider(
shipmentTrack: barcode.barcodes.first.rawValue!,
dateNow: dateNow,
));
получает данные, снова вызывается построитель для построения загруженных данных. Однако в этом случае ваш shipmentoutdataref изменится в процессе, так как dateNow будет другим, и, таким образом, вы окажетесь с другим поставщиком (т. Этот новый провайдер будет находиться в состоянии загрузки, и как только он получит данные, произойдет та же последовательность. Возможно, вы сможете исправить это, переместив dateNow куда-нибудь внутри провайдеров, а не в «инициализатор», если это возможно.
Вы еще не совсем там. Ваш getShipmentOutDataProvider является семейным поставщиком (riverpod.dev/docs/concepts/modifiers/family). Это означает, что это провайдер, который может принимать дополнительные аргументы (в вашем старом коде: shippingTrack и dateNow). Идея этих провайдеров заключается в том, что их возвращаемое значение может отличаться в зависимости от этих аргументов, но остается тем же самым, если аргументы остаются прежними. Если вы вызовете провайдера с теми же аргументами, он запомнит, что вы вызывали его раньше, и будет использовать те же данные, но с другими аргументами, это будет совершенно другой провайдер.
В вашем FutureBuilder каждый раз, когда вызывается строитель, dateNow будет создаваться снова (поэтому не каждый раз, когда изменяется время, а каждый раз, когда виджет создается снова), и поэтому аргументы вашего familyprovider меняются. Поэтому будет создан провайдер, отличный от провайдера из более ранней сборки, и, таким образом, он все еще будет находиться в состоянии загрузки. При перемещении dateNow внутри провайдера аргументы не меняются при каждой сборке виджета, поэтому он «запомнит» провайдера из более раннего и будет использовать его готовое состояние.
да, я сделал то, что вы сказали, и переместил переменную dateNow из виджета в мой провайдер, и это устранило проблемы. Большое спасибо! Так что в моем понимании. в основном DateTime.now() будет постоянно перезапускаться, что заставит ref.watch продолжать запускать состояние загрузки без остановок? Я правильно понимаю задачу?