Skip to content

ArpitAswal/GoRouter_Navigation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ—ΊοΈ GoRouter in Flutter β€” Complete Learning Project

A fully annotated Flutter project implementing every concept, built as a working shopping app demo with an interactive concepts hub.


πŸ“– What You Will Learn

This project teaches you 8 core GoRouter concepts through working, commented code:

# Concept File(s)
1 Defining Routes (GoRoute) config/route_config.dart
2 Creating the Router (GoRouter) config/route_config.dart, main.dart
3 Navigation Methods (go, push, goNamed, pop) screens/demo_screens.dart
4 Query Parameters screens/product_list_screen.dart, screens/product_details_screen.dart
5 Path Parameters screens/product_details_screen.dart, screens/product_purchase_screen.dart
6 Sub-Routes (Nested Routes) config/route_config.dart, screens/demo_screens.dart
7 ShellRoute (Persistent UI) screens/shell_route_demo.dart
8 Redirection & Exit Guards config/route_config.dart, screens/demo_screens.dart

πŸ—‚οΈ Project Structure

lib/
β”œβ”€β”€ main.dart                          # App entry point β€” MaterialApp.router()
β”œβ”€β”€ config/
β”‚   └── route_config.dart              # ⭐ Central GoRouter config β€” all routes defined here
β”œβ”€β”€ models/
β”‚   └── product.dart                   # Product data model (immutable data class)
β”œβ”€β”€ controller/
β”‚   └── product_controller.dart        # Data access layer (in-memory product store)
β”œβ”€β”€ screens/
β”‚   β”œβ”€β”€ concepts_overview_screen.dart  # 🏠 Hub screen β€” links to all demos
β”‚   β”œβ”€β”€ product_list_screen.dart       # Shopping app: Product grid (uses goNamed + queryParams)
β”‚   β”œβ”€β”€ product_details_screen.dart    # Shopping app: Detail view (Hero animation, path params)
β”‚   β”œβ”€β”€ product_purchase_screen.dart   # Shopping app: Purchase screen (onExit guard)
β”‚   β”œβ”€β”€ demo_screens.dart              # Individual demo screens for each concept
β”‚   └── shell_route_demo.dart          # ShellRoute with BottomNavigationBar
└── widgets/
    β”œβ”€β”€ single_product.dart            # Product card with Hero animation
    β”œβ”€β”€ bottom_container.dart          # Price + Buy Now bottom sheet widget
    β”œβ”€β”€ search_section.dart            # Search TextField widget
    β”œβ”€β”€ ratings.dart                   # Star rating row widget
    β”œβ”€β”€ color_container.dart           # Color swatch widget
    └── show_modal.dart                # Full-size image dialog widget

πŸš€ Getting Started

Prerequisites

  • Flutter SDK (3.x+)
  • Dart 3.x
  • Android Studio / VS Code with Flutter plugin

Run the App

# Clone and navigate to the project
cd GoRouterNavigation

# Install dependencies
flutter pub get

# Run the app
flutter run

πŸ“š Concepts Deep Dive

1. Installation & Setup

Add go_router to pubspec.yaml:

dependencies:
  go_router: ^17.0.0

Import in your Dart files:

import 'package:go_router/go_router.dart';

2. How to Define Routes (GoRoute)

Each GoRoute defines one screen with a URL path and a builder function:

GoRoute(
  path: '/',
  name: 'home',             // Optional name for goNamed() navigation
  builder: (context, state) => const HomeScreen(),
),

Key insight: state in the builder gives you access to URL parameters, the current URI, and other route metadata.

πŸ“ See: lib/config/route_config.dart


3. How to Create the Router (GoRouter)

// lib/config/route_config.dart
final GoRouter router = GoRouter(
  initialLocation: '/',
  debugLogDiagnostics: true, // Logs every navigation to console
  routes: <RouteBase>[
    GoRoute(path: '/', builder: (context, state) => const HomeScreen()),
    // ... more routes
  ],
);

In main.dart, pass it to MaterialApp.router():

MaterialApp.router(
  routerConfig: router, // ← The key integration point
)

Why MaterialApp.router()? GoRouter uses Flutter's Navigator 2.0 (Router API). MaterialApp.router() is the constructor that accepts a RouterConfig object (which GoRouter implements).

πŸ“ See: lib/main.dart | lib/config/route_config.dart


4. How to Navigate Between Screens

GoRouter provides three main navigation methods:

Method Behaviour Use When
context.go('/path') Replaces current route Login β†’ Home (no back)
context.push('/path') Pushes on stack List β†’ Detail (back works)
context.goNamed('name') Navigate by route name Avoiding hardcoded paths
context.pop() Go back Back button equivalent
// Navigate by path β€” replaces current route
context.go('/products');

// Navigate by path β€” pushes on stack
context.push('/products');

// Navigate by name
context.goNamed('product-details', queryParameters: {'id': 'p1'});

// Also valid (interops with GoRouter)
Navigator.of(context).pop();

πŸ“ See: lib/screens/demo_screens.dart


5. How to Pass Query Parameters

Query parameters are optional key-value pairs appended after ? in the URL.

Sending (from ProductListScreen):

context.goNamed(
  'product-details',
  queryParameters: {'id': product.id},
);
// Resulting URL: /products/product-details?id=p1

Receiving (in route_config.dart builder):

GoRoute(
  path: 'product-details',
  name: 'product-details',
  builder: (context, state) {
    return ProductDetailsScreen(
      productId: state.uri.queryParameters['id'] ?? '',
    );
  },
),

When to use query params? When the data is optional, when you want multiple params without changing the route structure, or when the parameter is a filter/search value.

πŸ“ See: lib/screens/product_list_screen.dart


6. How to Pass Path Parameters

Path parameters are embedded directly in the URL path. They are required β€” the route doesn't exist without them.

Defining the route (in route_config.dart):

GoRoute(
  path: 'product-purchase/:description', // :description is the dynamic segment
  name: 'pay-now',
  builder: (context, state) {
    return ProductPurchaseScreen(
      description: state.pathParameters['description']!, // ← Read path param
      productImage: state.uri.queryParameters['img']!,  // ← Read query param
    );
  },
),

Navigating with path params:

context.goNamed(
  'pay-now',
  pathParameters: {'description': product.description},
  queryParameters: {'img': product.imageUrl, 'price': '29.99'},
);
// URL: /products/product-details/product-purchase/Great+Watch?img=...&price=29.99

When to use path params? When the value is required and defines the route identity (IDs, slugs, usernames).

πŸ“ See: lib/screens/product_details_screen.dart


7. Sub-Routes (Nested Routes)

Sub-routes let you group related routes under a parent. The child path is relative to the parent.

GoRoute(
  path: '/profile',
  builder: (context, state) => const ProfileScreen(),
  routes: [
    // Relative path β†’ full URL: /profile/settings
    GoRoute(
      path: 'settings',
      builder: (context, state) => const SettingsScreen(),
    ),
  ],
),
URL Screen
/profile ProfileScreen
/profile/settings SettingsScreen

πŸ“ See: lib/config/route_config.dart | lib/screens/demo_screens.dart


8. ShellRoute (Persistent Bottom Navigation)

ShellRoute wraps child routes with a persistent UI shell (like a BottomNavigationBar). The shell stays mounted while only the inner content changes.

ShellRoute(
  builder: (context, state, child) {
    // 'child' = the currently active tab's widget (auto-injected by GoRouter)
    return ShellScaffold(child: child);
  },
  routes: [
    GoRoute(path: '/shell/home',    builder: (c, s) => const ShellHomeTab()),
    GoRoute(path: '/shell/explore', builder: (c, s) => const ShellExploreTab()),
    GoRoute(path: '/shell/profile', builder: (c, s) => const ShellProfileTab()),
  ],
),

The ShellScaffold renders the BottomNavigationBar and displays child in its body. When you tap a tab, GoRouter updates child β€” the scaffold itself is never rebuilt.

πŸ“ See: lib/screens/shell_route_demo.dart


9. Redirection (Route Guards)

redirect runs before the route builder. Return null to proceed, or return a path string to redirect.

Route-level redirect (protecting a single route):

GoRoute(
  path: '/dashboard',
  redirect: (context, state) {
    return AppState.isLoggedIn ? null : '/login'; // Redirect if not logged in
  },
  builder: (context, state) => const DashboardScreen(),
),

Role-based guard:

GoRoute(
  path: '/admin',
  redirect: (context, state) {
    return AppState.isAdmin ? null : '/not-authorized';
  },
  builder: ...
),

Redirect old URLs:

GoRoute(
  path: '/old-home',
  redirect: (context, state) => '/', // Always redirect to new home
),

πŸ“ See: lib/config/route_config.dart | lib/screens/demo_screens.dart


10. Exit Guards (onExit)

onExit intercepts navigation away from a screen. Return true to allow leaving, false to cancel.

GoRoute(
  path: 'product-purchase/:description',
  builder: ...,
  onExit: (context, state) async {
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (_) => AlertDialog(
        title: const Text('Leave Purchase?'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context, false), // Stay
            child: const Text('Stay'),
          ),
          TextButton(
            onPressed: () => Navigator.pop(context, true),  // Leave
            child: const Text('Leave'),
          ),
        ],
      ),
    );
    return confirmed ?? false; // Default: stay (false)
  },
),

When to use onExit? Purchase screens, forms with unsaved data, checkout flows β€” anywhere you need to confirm before the user leaves.

πŸ“ See: lib/config/route_config.dart


πŸ›οΈ Shopping App Flow

The main demo is a minimalist shopping app that chains all GoRouter concepts:

ProductListScreen (/)
  β”‚
  β”‚  context.goNamed('product-details', queryParameters: {'id': product.id})
  β”‚  URL: /products/product-details?id=p1
  β–Ό
ProductDetailsScreen
  β”‚
  β”‚  context.goNamed('pay-now', pathParameters: {'description': ...},
  β”‚                             queryParameters: {'img': ..., 'price': ..., 'name': ...})
  β”‚  URL: /products/product-details/product-purchase/Great+Watch?img=...
  β–Ό
ProductPurchaseScreen
  β”‚
  β”‚  ← onExit guard fires when user tries to go back
  β”‚    Shows confirmation dialog
  β–Ό
Back to ProductDetailsScreen (if confirmed)

πŸ—οΈ Architecture: Clean Layered Structure

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    Screens   β”‚  ← UI only. No direct data access. Calls controllers.
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   Widgets    β”‚  ← Reusable UI pieces. Receive data as parameters.
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Controllers β”‚  ← Business logic. Fetches/manages data.
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚    Models    β”‚  ← Pure data classes. No UI, no logic.
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚    Config    β”‚  ← Navigation wiring. All routes in one place.
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”‘ Key Takeaways

  1. Use MaterialApp.router(routerConfig: router) β€” not the old routeInformationParser + routerDelegate pattern.

  2. Always use static const routeName on each screen class to keep route names consistent and avoid typos.

  3. Query params for optional data, path params for required data β€” both patterns shown in the shopping flow.

  4. ShellRoute solves the persistent bottom nav problem elegantly β€” the shell stays mounted, only child changes.

  5. redirect() returns null (proceed) or a path string (redirect) β€” use it for auth, role-based access, and URL migrations.

  6. onExit() returns a Future<bool> β€” false cancels navigation, true allows it.

  7. Sub-routes keep related screens grouped β€” child paths are relative, automatically prefixed by parent path.

  8. debugLogDiagnostics: true on GoRouter prints all navigation events β€” turn it off for production.


πŸ“¦ Dependencies

dependencies:
  flutter:
    sdk: flutter
  go_router: ^17.0.0

πŸ“„ Reference


Built as a comprehensive Flutter learning resource β€” every line is commented to explain the "why", not just the "what".


App View Screenshots

Screenshot_20260502_130327 Screenshot_20260502_130338 Screenshot_20260502_130346 Screenshot_20260502_130354 Screenshot_20260502_130404

About

This repository delves deep into every detail of go_router, guiding you from setup to advanced features like redirection and nested routes. go_router is a flexible and lightweight routing library for Flutter that simplifies the navigation process and provides a clean API for managing routes, passing parameters, and handling redirects.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors