Flutter Web - Fix Refresh & Back button Problem
Tags: flutter, web, refresh, back
Published: 2022-04-24 03:55:00


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1wvbvg04uet73zd2hbt2.gif)

## Update Notice!!!

The explaination below is somewhat outdated. Now, I recommends you to use [go_router](https://pub.dev/packages/go_router), a routing package using Flutter Navigation 2.0!

## Intro

When I’m on a flutter web, I faced with routing issue. Both `MaterialApp` and `GetMaterialApp` had the same issues, which was routing acts weird when browser’s back button and refresh button are clicked. So I’ve tried some test project with flutter web and I found the solution. Now, it works just like native web project. I’d like to share this solution with you. 

## Flutter Navigation 2.0

There is this thing called `Flutter Navigation 2.0` . I didn’t dig much about it, but to simply put, it’s navigation system is now more customizable with this Navigation 2.0.

Since the original routing system had so many problems in web platform, I had to try this one. And it worked, thankfully. You can use with `MaterialApp.router` instead of just `MaterialApp` . But if you do that you need to implement some override method which involves in navigation logic. Instead overriding each methods, I used `GetMaterialApp.router` which comes with default methods, and therefore, only extra thing to do is just build method.

## Code Implementation

## Install Getx

At this moment, I used below version of `Getx` package.

```yaml
dependencies:
  ...
  get: ^4.6.1
```

## Basic Routing Stuff

For convenience, I used simple routing path and getPages with snippet.

```dart
abstract class Routes {
  static const HOME = '/';
  static const LOGIN = '/login';
  static const SIGNUP = '/signup';
}
```

```dart

abstract class AppPages {
  static final pages = [
    GetPage(
      name: Routes.HOME,
      page: () => Home(),
    ),
    GetPage(
      name: Routes.LOGIN,
      page: () => Login(),
    ),
    GetPage(
      name: Routes.SIGNUP,
      page: () => Signup(),
    ),
  ];
}
```

## Create `GetMaterialApp.router`

When you use `GetMaterialApp.router` instead of just `GetMaterialApp` , you don’t need to provide(and you can’t) `initialRoute` . But you need to provide `getPages` and `routerDelegate` fields with values.

```dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() {
  runApp(GetMaterialApp.router(
    debugShowCheckedModeBanner: false,
    defaultTransition: Transition.fade,
    getPages: AppPages.pages,
    routerDelegate: AppRouterDelegate(),
  ));
}
```

## Create Sample Pages

For testing, I created some simple test pages with different background colors.

- Note that when you navigate between pages, you need to use `Get.rootDelegate` instead of `Get` because we’re using `routerDelegate` to handle routing.

```dart
class Home extends StatelessWidget {
  const Home({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      child: TextButton(
        child: Text(
          'Home',
          style: TextStyle(color: Colors.white),
        ),
        onPressed: () => Get.rootDelegate.toNamed(Routes.LOGIN),
      ),
    );
  }
}

class Login extends StatelessWidget {
  const Login({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.orange,
      child: TextButton(
        child: Text(
          'Login',
          style: TextStyle(color: Colors.white),
        ),
        onPressed: () => Get.rootDelegate.toNamed(Routes.SIGNUP),
      ),
    );
  }
}

class Signup extends StatelessWidget {
  const Signup({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.blue,
      child: TextButton(
        child: Text(
          'Signup',
          style: TextStyle(color: Colors.white),
        ),
        onPressed: () => Get.rootDelegate.toNamed(Routes.HOME),
      ),
    );
  }
}
```

## Create router delegate with `GetDelegate`

So, this is the main part. 

- Create `AppRouterDelegate` or what ever you like to call with `GetDelegate` extended.
- Override `build` method and return `Navigator` with `onPopPage` and `pages` .
    - `onPopPage` → This is invoked when pop action happened, and return wheather pop is successful or not. If you don’t want to block pop action, just leave it there with default code.
    - `pages` → This is different from `getPages` . This is more related to what page to show in current moment. I’m not fully figured out yet, but it’s also different from navigation history stack. So, in order to show the right page according to current url, I used `currentConfiguration.currentPage` . Note that this field can’t be empty since it related to current view. When `currentConfiguration` is null(which means first entered the page), you can just simply return initial page.

```dart

class AppRouterDelegate extends GetDelegate {
  @override
  Widget build(BuildContext context) {
    return Navigator(
      onPopPage: (route, result) => route.didPop(result),
      pages: currentConfiguration != null
          ? [currentConfiguration!.currentPage!]
          : [GetNavConfig.fromRoute(Routes.HOME)!.currentPage!],
    );
  }
}
```

And plus, since you can write `build` method and other override method(if you want to customize login) you can easily add user authentication status check before navigate to any page.

## Conclusion

I think Flutter Web has a long way to go, but I’m glad Flutter is keeping up there work! I hope this article can help those who struggles with Flutter Web routing issue.

Cheers!

<a href="https://www.buymeacoffee.com/swimmingkiim" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/arial-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>