genericUser
genericUser

Reputation: 7108

Flutter remove all routes using auto_route

In case of error, I want to redirect my users to the same flow again (in order to reset the flow state).

I'm using the auto_route package for navigation, and I can see that router.replace and router.replaceAll do not replace (remove and insert from the stack) the same routes again (it just updates them).

From the official documentation:

// removes last entry in stack and pushs provided route            
// if last entry == provided route page will just be updated
router.replace(const BooksListRoute())

// This's like providing a completely new stack as it rebuilds the stack          
// with the list of passed routes          
// entires might just update if already exist          
router.replaceAll([          
   LoginRoute()          
]);          

How can I "hard reset" replace a route, or stack of routes, using auto_route package?

Upvotes: 3

Views: 4857

Answers (4)

Saurabh Sangam
Saurabh Sangam

Reputation: 11

After multiple attempts and failures while trying to use the replaceAll with updateExistingRoutes: false approach, I was able to implement redirect and reload functionality in our application with two distinct approaches:

Approach 1: Reload Entire App For a complete application reload, I utilized the Phoenix.rebirth() method from the flutter_phoenix package. This method restarts the entire application, providing a clean state immediately after redirection.

void performRedirectAndRebirth(BuildContext context) {
      // Perform the navigation
      context.router.replaceAll([YourNewPageRoute()]);

      // After navigation, restart the entire application
      Phoenix.rebirth(context);
    }

Approach 2: Invalidate State Using Riverpod In scenarios where a full app reload isn't necessary, I used Riverpod's ref.invalidate function to selectively invalidate the state. This method is more granular and avoids the overhead of a complete app restart:

    void performRedirectAndInvalidateState(WidgetRef ref, BuildContext context) {
      // Perform the navigation
      context.router.replaceAll([YourNewPageRoute()]);

      // Invalidate a specific provider to refresh its consumers
      ref.invalidate(someProvider);
    }

Upvotes: 0

Guillem Poy
Guillem Poy

Reputation: 794

This is a solution I found and posted in GitHub: https://github.com/Milad-Akarie/auto_route_library/issues/1964#issuecomment-2141828649

Even though it is not 100% ideal, it gets you 90% of the way (I am only missing that I don't feel completely safe using it).

These are my final methods to rebuildAll and popAllAndPushAll:

  void rebuildAll() {
    List<RouteData> routesDataList = stack.map((e) => e.routeData).toList();
    List<PageRouteInfo<dynamic>> routeInfos = routesDataList.map((routeData) => PageRouteInfo.fromMatch(routeData.topMatch)).toList();

    if (routeInfos.isNotEmpty) {
      popAllAndPushAll(routeInfos);
    }
  }

  void popAllAndPushAll(List<PageRouteInfo<dynamic>> routeInfos) {
    List<RouteData> routesInStack = stack.map((e) => e.routeData).toList();

    /*await*/ pushAndPopUntil(routeInfos.first, predicate: (_) => false); // This never finishes the future. ISSUE: https://github.com/Milad-Akarie/auto_route_library/issues/1964
    if (routeInfos.length > 1) WidgetsBinding.instance.addPostFrameCallback((_) => pushAll(routeInfos.skip(1).toList()));
  }

Upvotes: 0

genericUser
genericUser

Reputation: 7108

Solved.

In order to "hard reset" the same page using auto_route package, Use pushAndPopUntil function, with a predicate set to always false.

That way, all pages will be removed, and the provided stack will be inserted instead (in other words, a full replacement, even for the same page).

Then your page will reinitiate, and all state values will be reset (same as redirecting to a new page).

await _router.pushAndPopUntil(
    const LoginRoute(),
    predicate: (_) => false,
)

Upvotes: 3

Tasnuva Tavasum oshin
Tasnuva Tavasum oshin

Reputation: 4740

Add this package :

dependencies:
  flutter_phoenix: ^1.1.0

Example:

void main() {
  runApp(
    Phoenix(
      child: App(),
    ),
  );
}

Phoenix.rebirth(context);

Phoenix restarts your application at the application level, rebuilding your application widget tree from scratch, losing any previous state.

Phoenix does not fully restart your application process at the OS level.

Upvotes: 1

Related Questions