Home > OS >  Flutter Riverpod show CircularProgressIndicator while waiting for future ro resolve
Flutter Riverpod show CircularProgressIndicator while waiting for future ro resolve

Time:01-27

I want to show CircularProgressIndicator while waiting for future to resolve using flutter_riverpod, here is my code snippet. But it's not showing, I am using ConsumerStatefulWidget is this right way to do it?

ElevatedButton(
                    onPressed: () {
                      rejectResponse = ref
                          .read(notificationRepositoryProvider)
                          .approveDocument(1);
                      Navigator.of(context).pop();
                      setState(() {});
                    },
                    child: FutureBuilder(
                        future: rejectResponse,
                        builder: (context, snapshot) {
                          if (snapshot.connectionState ==
                              ConnectionState.done) {
                            if (snapshot.hasData) {
                              return Text('Yes');
                            } else if (snapshot.hasError) {
                              return Text('Error');
                            }
                          } else if (snapshot.connectionState ==
                              ConnectionState.waiting) {
                            return CircularProgressIndicator();
                          }
                          return Text('Yes');
                        }),
                  ),

CodePudding user response:

You can use ConnectionState, but I think it can also be in none state. So you can check if its done, and if not, you should probably show the loading indicator anyway.

builder: (context, snapshot) {
   if (snapshot.connectionState != ConnectionState.done) {
      return CircularProgressIndicator();
   } 
   else 
      return Text('Yes');
   } 
}

I usually use the hasData property instead. This lets me reduce the number of states I have to deal with, and safely assume snapshot.data is not null. I use the below pattern.

// strongly type the builder so snapshot.data is typed as well.
FutureBuilder<MyType>( 
    future: myFuture
    builder: (context, snapshot) {
       if (!snapshot.hasData) return Loading();

       final data = snapshot.data!; // '!' is safe since hasData is true
       return DisplayData(data);
    }
)

CodePudding user response:

The preferred way of doing this in Riverpod is using a FutureProvider and AsyncValue:

final notificationRepositoryProvider = FutureProvider<bool?>((ref) async {
  Future<bool> approveDocument() => Future.delayed(Duration(seconds: 2), () => Future.value(Random().nextBool()));

  return approveDocument();
});

class HomeView extends ConsumerStatefulWidget {
  const HomeView({Key? key}) : super(key: key);

  @override
  HomeViewState createState() => HomeViewState();
}

class HomeViewState extends ConsumerState<HomeView> {
  @override
  Widget build(BuildContext context) {
    AsyncValue<bool?> rejectResponse = ref.watch(notificationRepositoryProvider);
    return ElevatedButton(
        onPressed: () {
         ref.refresh(notificationRepositoryProvider.future);
        },
        child: rejectResponse.when(
          loading: () => const CircularProgressIndicator(
            color: Colors.white,
          ),
          skipLoadingOnRefresh: false,
          error: (err, stack) => Text('Error'),
          data: (data) => Text('Yes: $data'),
        ));
  }
}

Note that after the initial loading, the FutureProvider will return the previous value but will set AsyncValue.isRefreshing to true. To avoid this and always show the loader on refresh, you can set skipLoadingOnRefresh to false.

  • Related