Search code examples
flutterdartriverpodappwrite

The method 'when' isn't defined for the type 'Object'


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;
});

Solution

  • 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.

    Code sample:

    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'],
            );
          },
        );
      }
    }
    

    Try the full example on DartPad