My code works perfectly fine without the family modifier, but as soon as I add it, I can't seem to retrieve the state data - it just comes back empty. I'm confused because I've checked the state value while saving it from the API and it's definitely not empty. What could be causing this issue?
This is my state Notifier
class SingleRequestNotifier extends StateNotifier<Request> {
SingleRequestNotifier({this.ref, this.lang, this.requestID})
: super(Request.initial()) {
fetchSingleRequestData(lang: lang, requestID: requestID);
}
final Ref? ref;
final String? lang;
final String? requestID;
final RequestServices dataService = GetIt.instance<RequestServices>();
Request get getSingleRequest {
return state;
}
Future fetchSingleRequestData({String? lang, String? requestID}) async {
try {
await dataService
.getSingleRequestList(lang: lang!, requestID: requestID!)
.then((value) {
state = value;
print(value.category); // here value is printing
ref!.read(isLoadingProvider.notifier).state = false;
});
} catch (e) {
rethrow;
}
}
}
This is my provider
final singleRequestStateProvider =
StateNotifierProvider.family<SingleRequestNotifier, Request, Map<String,dynamic>>(
(ref, arg) {
return SingleRequestNotifier(
ref: ref,
lang: arg['lang'],
requestID: arg['requestID']);
});
This is how i'm trying to get the data
Map<String, dynamic> args = {
'lang': 'en-AE',
'requestID': widget.requestID
};
Request _request = ref.watch(singleRequestStateProvider(args));
print(_request.category); // here value is empty
By default, Dart checks for referential equality. If we compare any two non-constant objects in dart with the same value, it evaluates to false.
final first = {
'lang': 'en-AE',
'requestID': 1
};
final second = {
'lang': 'en-AE',
'requestID': 1
};
print(first == second); // false
From riverpod documentation https://riverpod.dev/docs/concepts/modifiers/family
Parameter restrictions For families to work correctly, it is critical for the parameter passed to a provider to have a consistent hashCode and ==.
Ideally, the parameter should either be a primitive (bool/int/double/String), a constant (providers), or an immutable object that overrides == and hashCode.
So first create an object to pass as argument to provider.
@immutable
class SingleRequestArguments {
final String lang;
final int id;
const SingleRequestArguments({
required this.lang,
required this.id,
});
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is SingleRequestArguments &&
runtimeType == other.runtimeType &&
lang == other.lang &&
id == other.id;
@override
int get hashCode => lang.hashCode ^ id.hashCode;
}
Then in you code replace the map that you used to pass as an argument to this object.
final singleRequestStateProvider =
StateNotifierProvider.family<SingleRequestNotifier, Request, SingleRequestArguments>((ref, arg) {
return SingleRequestNotifier(ref: ref, lang: arg.lang, requestID: arg.id);
});
final args = SingleRequestArguments(
lang: 'en-AE',
id: widget.requestID,
);
Request _request = ref.watch(singleRequestStateProvider(args));