Search code examples
flutterdartriverpodgorouter

flutter: how to reload screen every time user navigate to it


I have a screen that has to be reloaded (fetch new data from API) every time user navigates to in (even when the user pressed the back button).

I'm working with AsyncValue and GoRouter among riverpod

here's the screen code

class BatchScreen extends ConsumerWidget {
  static const String screenPath = "/BatchScreen";
  const BatchScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final AsyncValue<BatchModel?> btachController =
        ref.watch(batchControllerProvider);
    final AuthRepository authRepository = ref.watch(authRepositoryProvider);
    ref.listen<AsyncValue<void>>(
      batchControllerProvider,
      (_, state) => state.whenOrNull(
        error: (error, stackTrace) {
          // show snackbar if an error occurred
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: Text(
                error.toString(),
              ),
            ),
          );
        },
      ),
    );
    Size size = MediaQuery.of(context).size;
    bool isBegin = false;
    return SafeArea(
      child: Stack(
        children: [
          Scaffold(
            appBar: PreferredSize(
              preferredSize: const Size.fromHeight(250),
              child: CustomeAppBar(
                dynamicWidget: Expanded(
                  flex: 6,
                  child: UserInfo(
                    userId: authRepository.userModel.id,
                    fullName: authRepository.userModel.name,
                    warehouse: 'casablanca',
                  ),
                ),
              ),
            ),
            body: Container(
              alignment: Alignment.center,
              padding: const EdgeInsets.all(16),
              child: Column(
                mainAxisAlignment: (isBegin)
                    ? MainAxisAlignment.spaceAround
                    : MainAxisAlignment.center,
                children: [
                  Column(
                    children: [
                      (isBegin)
                          ? CustomButton(
                              ontap: () {
                                GoRouter.of(context).pushNamed(
                                  APP_PAGE.palettQrCode.toName,
                                );
                              },
                              width: size.width / 1.2,
                              height: size.height / 12,
                              text: context.loc.continuee,
                              colorText: Colors.white,
                              backgroundColor: colorPrimary,
                            )
                          : StartButton(
                              ontap: () {
                                bool test = false;
                                QuickAlert.show(
                                  context: context,
                                  type: QuickAlertType.confirm,
                                  text: 'Do you want to logout',
                                  confirmBtnText: 'Yes',
                                  cancelBtnText: 'No',
                                  confirmBtnColor: Colors.green,
                                  onConfirmBtnTap: () async {
                                    // on error
                                    if (test) {
                                      await QuickAlert.show(
                                        context: context,
                                        type: QuickAlertType.error,
                                        text: 'Please input something',
                                      );
                                      return;
                                    }
                                    Navigator.pop(context);
                                    QuickAlert.show(
                                      context: context,
                                      type: QuickAlertType.loading,
                                      title: 'Loading',
                                      text: 'Fetching your data',
                                      barrierDismissible: false,
                                    );
                                    await Future.delayed(
                                      Duration(milliseconds: 3000),
                                      () async {
                                        if (context.mounted) {
                                          Navigator.pop(context);
                                          GoRouter.of(context).pushNamed(
                                            APP_PAGE.palett.toName,
                                          );
                                        }
                                      },
                                    );
                                  },
                                );
                              },
                            ),
                      const SizedBox(height: 20),
                      if (isBegin)
                        CustomButton(
                          ontap: () {
                            GoRouter.of(context).pop();
                          },
                          width: size.width / 1.2,
                          height: size.height / 12,
                          text: context.loc.close,
                          colorText: Colors.white,
                          backgroundColor: Colors.black,
                          borderColor: Colors.black,
                        ),
                    ],
                  ),
                  if (isBegin)
                    CustomButton(
                      ontap: () {
                        GoRouter.of(context).pop();
                      },
                      width: size.width / 1.2,
                      height: size.height / 12,
                      text: "Abondon",
                      colorText: Colors.red,
                      backgroundColor: Colors.white,
                      borderColor: Colors.red,
                    ),
                ],
              ),
            ),
          ),
          btachController.when(
            data: (data) {
              logDebug(data);
              return const Positioned(
                left: 23,
                top: 200,
                child: BatchProduct(
                  countProduct: 29,
                ),
              );
            },
            error: (error, stackTrace) {
              return Positioned(
                left: 23,
                top: 200,
                child: Container(
                  height: 100,
                  width: size.width / 1.12,
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(10),
                    boxShadow: [
                      BoxShadow(
                        color: Colors.grey.withOpacity(0.4),
                        spreadRadius: 4,
                        blurRadius: 5,
                      ),
                    ],
                  ),
                  child: const Center(
                    child: Text(
                      'Uh oh. Something went wrong!',
                      style: TextStyle(
                        fontSize: 20,
                        color: Colors.black,
                        decoration: TextDecoration.none,
                        fontFamily: 'almarai',
                      ),
                    ),
                  ),
                ),
              );
            },
            loading: () {
              return Positioned(
                left: 23,
                top: 200,
                child: Container(
                  height: 100,
                  width: size.width / 1.12,
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(10),
                    boxShadow: [
                      BoxShadow(
                        color: Colors.grey.withOpacity(0.4),
                        spreadRadius: 4,
                        blurRadius: 5,
                      ),
                    ],
                  ),
                  child: const Center(
                    child: CircularProgressIndicator(),
                  ),
                ),
              );
            },
          ),
        ],
      ),
    );
  }
}

I'm using a controller to handle all the functional work

class BatchController extends StateNotifier<AsyncValue<BatchModel?>> {
  final BatchRepository batchRepository;
  BatchController({required this.batchRepository})
      : super(const AsyncValue.data(null)) {
    getBatch();
  }

  Future<void> getBatch() async {
    try {
      state = const AsyncValue.loading();

      await Future.delayed(Duration(milliseconds: 2000));
      final List<BatchModel> bacth = await batchRepository.getBatch();
      state = AsyncValue.data(bacth.first);
      logDebug('hello');
      logDebug(state);
    } on DioError catch (e) {
      state = AsyncValue.error(
        "Uh oh. Something went wrong!",
        StackTrace.current,
      );
    }
  }
}

final batchControllerProvider =
    StateNotifierProvider<BatchController, AsyncValue<BatchModel?>>(
  (ref) {
    final batchRepository = ref.read(batchRepositoryProvider);

    return BatchController(batchRepository: batchRepository);
  },
);

the problem is when the user land on the screen for the first time the API calls and get the data but if the user navigates back or goes to a new screen and comes back to this screen the user gets the same previous data (without recalling API).

the point is I want to make an API call every time the user land on this screen.


Solution

  • The GoRouter is this:

    Inheritance Object > ChangeNotifier > GoRouter

    which means it is possible to add the required action via the addListener method (and remove it via ref.onDispose when the BatchController class is no longer in use).

    The point is to get an instance of GoRouter and in the initialization of the class BatchController add a method in which based on the route will be called to update the state (/data).

    For some more information you can go to this repository, it gives you a new look at the Riverpod + GoRouter bundle.