How to Use GoRouter for Efficient Navigation in Flutter
Published: 2023-02-24 15:26:21

Navigation, or how users switch between screens, is an important concept to master. Good navigation keeps your app organized and helps users find their way around without getting frustrated.

**Introducing Navigation**

Navigation in Flutter refers to the process of moving between different screens or pages within an application. In Flutter, you use a Navigator widget to manage your screens or pages, Think of screens and pages as routes.

A **stack** is a data structure that manages pages. You insert the elements last-in, first- out (LIFO), and only the element at the top of the stack is visible to the user.

**Navigator 2.0 Overview**

Navigation 2.0 is a new navigation system introduced in Flutter 2.0 that provides a more powerful and flexible way to navigate between screens in a Flutter app. It is built on top of the Flutter Navigator widget but provides several new features and improvements over the original navigation system, Navigation 1.0.

Some of the key features of Navigation 2.0 include:

- Navigator 2.0: Navigation 2.0 introduces a new Navigator widget, called Router, which provides a more flexible and powerful way to manage a stack of routes. It allows you to define your own routing logic and provides several new methods for navigating between screens.

- Deeplinking: Navigation 2.0 supports deeplinking, which allows you to navigate to a specific screen in your app based on a URL or other external input. This can be useful for integrating your app with other apps or services.

- Named Parameters: Navigation 2.0 supports named parameters, which allows you to pass parameters between screens using named parameters instead of relying on positional parameters. This can make your code more readable and easier to maintain.

**Why you should use go_router over Navigation API?**

GoRouter is a third-party package for navigation in Flutter that provides a simpler and more declarative approach to navigation than the Navigation API provided by Flutter. Here are a few reasons why you might consider using GoRouter over the Navigation API:

- Declarative API: GoRouter provides a declarative API for navigation that makes it easy to define routes and navigate between them using named routes. This can make your code easier to read and understand, and can reduce the amount of boilerplate code required for navigation.

- Dependency Injection: GoRouter supports dependency injection, which means you can pass data and dependencies between routes easily. This can make your code more modular and easier to test.

- Middleware Support: GoRouter supports middleware, which allows you to intercept and modify the navigation flow. This can be useful for implementing features like authentication, logging, and error handling.

Overall, while the Navigation API provided by Flutter is powerful and flexible, GoRouter provides a simpler and more declarative approach to navigation that can be easier to work with in certain cases. If you value a simpler, more declarative API.

So let's jump to go_router.

**What is go_router?**

go_router is a routing library for Flutter that simplifies navigation between pages and helps manage state in your application. It provides a declarative API for defining routes and makes it easy to pass data between pages. go_router is built on top of Flutter's Navigator 2.0 API, which provides a flexible way to manage app navigation and state.

**Getting Started with go_router**

Before we can use go_router in our Flutter application, we need to add it as a dependency in our pubspec.yaml file:

```
dependencies:
  go_router: ^6.1.0
```

Once we have added the dependency, we can import go_router in our Dart code:

```
import 'package:go_router/go_router.dart';
```
**Defining Routes**

The first step in using go_router is to define our application's routes. We can define routes by creating a GoRouter object and passing a list of RouteDefinition objects to its constructor. Each RouteDefinition represents a single route in our application and contains information about the route's path, the widget to display when the route is navigated to, and any parameters that should be passed to the widget.

create a new file and name it `app_router.dart` and write the following code.

```
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:gorouter/home.dart';
import 'package:gorouter/sub_home.dart';

final GoRouter router = GoRouter(
  routes: <GoRoute>[
    GoRoute(
      path: "/",
      name: "home",
      builder: (BuildContext context, GoRouterState state) {
        return const HomePage();
      },
    ),

    //
    GoRoute(
      path: "/sub",
      builder: (BuildContext context, GoRouterState state) {
        return const SubHome();
      },
    ),
  ],
);

```

In this code we start by importing necessary packages, then we create an instance `GoRouter` which accepts a list of `GoRoute` objects. Each `GoRoute` object represents a route in the application, with a unique `path` and a `builder` function.

The `builder` function is a callback function that is called by the `GoRouter` package to build the corresponding widget for a specific route. When the user navigates to a certain path defined in the `GoRoute`, the `GoRouter` will call the `builder` function associated with that route and pass in the current `BuildContext` and `GoRouterState` as arguments.

## But before we continue let's talk about Top-Level route and Sub-Route:

When you create a Top-Level this will generate a single page navigation stack but if you move to a Sub-Route the page will be added on top of the Top-Level route of the Sub-Route, and if you navigate to another Top-Level route it will create a new navigation stack.

Now navigate to `main.dart` page and update it to the following code.

```
import 'package:flutter/material.dart';
import 'package:gorouter/config/app_router.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // home: const Text('Flutter Demo Home Page'),
      routerConfig: router,
    );
  }
}

```

We have update our build method and it now returns `MaterialApp.router` witch now uses Router instead of Navigator.

`routerConfig` is a property of the `MaterialApp.router` widget in Flutter that allows you to configure various aspects of the app's navigation system. Specifically, it is used to configure the behavior of the app's `RouterDelegate` and `RouteInformationParser` objects, which are responsible for defining the app's routes and handling navigation events, respectively.

Now to navigate to a screen you can simply use `context.go('route')` or by using route name `context.goNamed("route name")`

example

```
ElevatedButton(
  onPressed: () {
    return context.goNamed("sub");
  },
  child: const Text("Go to sub page"),
),
```

See the full code sample in our GitHub repo [here](https://github.com/FlutterTanzania/go-router-demo) 

In this article we learned about basics of go_router package and why you should use it over Navigation 2.0