Flutter: GoRouter with ShellRoute
25-Jun-2024 - Sophoun
Hi, this is my third blog. This blog will explain to you how to use GoRouter
with the ShellRoute
in the Flutter application.
I think you already know about GoRouter
but here I will guide you all the setup to the usage of GoRouter
.
GoRouter
is a popular navigation library in the Flutter community. It provides us a way to handle navigation and Deeplink seamlessly. Without GoRouter
you will have a hard time implementing navigation using the traditional named route of Scaffold
or MaterialApp
.
Here I will write about how to use ShellRoute
only. If you're just starting with GoRouter
I suggest heading to my previous blog that explains about it suppurate
https://blog.sophoun.com/flutter-routing-using-gorouter
Ok, let's get into it in detail.
ShellRoute is a way that you have sub-navigation in your application like when you want to have a bottom navigation bar or sidebar for the web.
Imagine you have a login screen for your users and after they log in to the app they will see a sidebar of functionality and they can move around with those and the selection state still be in the right place.
The scenario above isn't easy if you don't apply ShellRoute
. Ok, let's apply coding.
I assume you already have a GoRouter defined in your application. So below is how you define ShellRoute in Flutter.
Here is my router.dart
file.
import 'package:go_router/go_router.dart'; import 'package:go_router_example/category_page.dart'; import 'package:go_router_example/dashboard_page.dart'; import 'package:go_router_example/home_page.dart'; import 'package:go_router_example/login_page.dart'; final goRouter = GoRouter( initialLocation: "/login", routes: [ GoRoute( path: '/login', builder: (context, state) => const LoginPage(), ), ShellRoute( builder: (context, state, child) => HomePage(child: child), routes: [ GoRoute( path: "/dashboard", builder: (context, state) => const DashboardPage(), ), GoRoute( path: "/category", builder: (context, state) => const CategoryPage(), ), ], ), ], );
As you see here, I define GoRouter and the initialize location is /login
that points to the GoRoute path /login
when the application starts.
I also have defined ShellRoute which has 2 children of GoRoute named /dashboard
and /category
. One thing the builder function of ShellRoute has a child that passes via parameter callback, it's a widget of its route that was navigated to. So this way you can design the sub-navigation as you wish in the HomePage
.
Here is the code in my home_page.dart
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class HomePage extends StatefulWidget { const HomePage({ super.key, required this.child, }); final Widget child; State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { int selectedIndex = 0; Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Home"), ), body: Row( children: [ NavigationRail( destinations: const [ NavigationRailDestination( icon: Icon(Icons.dashboard), label: Text("Dashboard"), ), NavigationRailDestination( icon: Icon(Icons.category), label: Text("Category"), ), ], selectedIndex: selectedIndex, labelType: NavigationRailLabelType.all, onDestinationSelected: (value) { selectedIndex = value; switch (value) { case 0: context.go("/dashboard"); break; case 1: context.go("/category"); break; default: throw Exception("Unknow destination"); } }, ), Expanded( child: widget.child, ) ], ), ); } }
Here I have defined a NavigationRail
that has 2 destinations, one to /dashboard
and one to /category
.
I also have a child widget that accepts via constructor and places it as a child. This child widget is a widget that passes via ShellRoute when it navigates.
By defined the goRouter
and HomePage
I can customize the navigation and easy to navigate between those children easily.
Below is the code in my login_page.dart
file
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class LoginPage extends StatefulWidget { const LoginPage({super.key}); State<LoginPage> createState() => _LoginPageState(); } class _LoginPageState extends State<LoginPage> { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Login"), ), body: Center( child: FilledButton( onPressed: () { context.go("/dashboard"); }, child: const Text("Login"), ), ), ); } }
Here is the result and available code.
Source code:
https://github.com/Sophoun/blogging_example/tree/main/flutter/go_router_example
That's all for today, if you have any questions or suggestions please comment.
Thank you for reading.