I created this StateNotifier with Riverpod in Flutter which Returns the Object DocumentsList
class TripStateNotifier extends StateNotifier<List<DocumentList>> {
TripStateNotifier() : super([]);
void getDocuments() async {
final res = await db.listDocuments(collectionId: '6286c0f1e7b7a5760baa');
state = res as List<DocumentList>;
}
}
final TripState = StateNotifierProvider((ref) => TripStateNotifier());
And this ConsumerWidget whicht gets the data
ref.watch(TripState)!.when(
data: (list) {
//Handeling if no data is found
if(list == null || (list.documents?.isEmpty ?? true)) return Center(child: Text("Yet you didn´t add any destinations to your trip", style: TextStyle(color: Colors.black.withOpacity(0.5)))); return ListView.builder(
itemCount: list.total,
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (context, index) {
return mytrip_card(
location: list.documents[index].data['location'], date: list.documents[index].data['date']
);
},
);
},
error: (e, s) => Text(e.toString()),
loading: () => const CircularProgressIndicator(),
),
My Problem is that my IDE Outputs following Error in regards to the when in ref.watch(TripState)!.when
The method 'when' isn't defined for the type 'Object'.
Intrestingly enought my Old Soulution with Future Provider worked why does this not?
Old solution:
final TripProvider = FutureProvider((ref)
async {
debugPrint('test');
final res = await db.listDocuments(collectionId: '6286c0f1e7b7a5760baa');
return res;
});
The method when
is only available for the object type AsyncValue
which can be provided by a FutureProvider
or a StreamProvider
.
Now that you are using a StateNotifierProvider
, you won't be able to use when
anymore, I would recommend you to create a "state" class to use with your TripStateNotifier
.
final tripStateProvider = StateNotifierProvider<TripStateNotifier, TripState>(
(ref) => TripStateNotifier());
class TripStateNotifier extends StateNotifier<TripState> {
TripStateNotifier() : super(const TripState());
void getDocuments() async {
// Trigger the loading state
state = state.copyWith(isLoading: true);
try {
final res = await db.listDocuments(collectionId: '6286c0f1e7b7a5760baa');
// Update the state with your newly fetched results
state = state.copyWith(
isLoading: false,
documents: res as List<DocumentList>,
);
} catch (e) {
// Manage received error
state = state.copyWith(
isLoading: false,
hasError: true,
);
}
}
}
@immutable
class TripState {
final bool isLoading;
final bool hasError;
final List<DocumentList> documents;
const TripState({
this.documents = const [],
this.isLoading = false,
this.hasError = false,
});
int get total => documents.length;
TripState copyWith({
List<DocumentList>? documents,
bool? isLoading,
bool? hasError,
}) {
return TripState(
documents: documents ?? this.documents,
isLoading: isLoading ?? this.isLoading,
hasError: hasError ?? this.hasError,
);
}
}
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final currentState = ref.watch(tripStateProvider);
final controller = ref.read(tripStateProvider.notifier);
if (currentState.isLoading) return const CircularProgressIndicator();
if (currentState.documents.isEmpty) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Yet you didn´t add any destinations to your trip",
style: TextStyle(
color: Colors.black.withOpacity(0.5),
),
),
TextButton(
onPressed: controller.getDocuments,
child: const Text('Refresh'),
),
],
),
);
}
return ListView.builder(
itemCount: currentState.total,
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (context, index) {
return MyTripCard(
location: currentState.documents[index].data['location'],
date: currentState.documents[index].data['date'],
);
},
);
}
}