Pada aplikasi dengan belasan layar, perintah Navigator.push yang tersebar di banyak callback membuat struktur navigasi sulit dibaca dan sulit diuji. Package go_router menata ulang navigasi dengan pendekatan deklaratif, yaitu daftar path dan layar yang menjadi satu-satunya rujukan struktur navigasi. Topik ini membahas kelemahan Navigator imperatif, penyusunan GoRouter dengan GoRoute, perbedaan context.go dan context.push, serta deep link, yaitu tautan yang membuka layar tertentu secara langsung.
Kelemahan Navigator imperatif#
Navigator bekerja secara imperatif, yaitu setiap perpindahan berupa perintah eksplisit yang dieksekusi segera ketika dipanggil. Struktur navigasi akibatnya tersebar di seluruh kode aplikasi dan tersembunyi di dalam onPressed, initState, serta callback lainnya. Daftar layar dan jalur menuju tiap layar tidak dapat dibaca dari satu tempat, melainkan harus disusun dari penelusuran kode.
Kondisi ini makin merepotkan pada aplikasi web dan perangkat seluler yang menerima tautan langsung. Sebuah URL perlu dipetakan ke layar yang tepat, dan pemetaan itu harus dibangun secara manual di samping Navigator. go_router menempatkan pemetaan tersebut sebagai konfigurasi deklaratif sekaligus menangani sinkronisasi URL.
Kerumitan ini juga menyulitkan pengujian dan orientasi anggota tim baru. Struktur yang tersebar harus direkonstruksi dengan membaca banyak berkas, sedangkan konfigurasi deklaratif cukup dibaca sekali untuk mengetahui seluruh layar dan jalur perpindahannya.
Menyusun GoRouter dan GoRoute#
Package go_router dipasang melalui perintah berikut pada direktori proyek.
# tidak-dijalankan
# menambahkan package go_router ke proyek
flutter pub add go_routerPerintah tersebut menambahkan entri go_router pada pubspec.yaml, lalu mengunduh paket beserta dependensinya secara otomatis. Versi yang terpasang dapat diperiksa pada berkas pubspec.lock. Contoh pada topik ini ditulis untuk go_router versi 18.x.
Inti konfigurasinya adalah objek GoRouter yang memuat daftar GoRoute. Setiap GoRoute mendeklarasikan path, yaitu pola URL layar, dan builder, yaitu fungsi yang menyusun widget layar dari GoRouterState. Daftar inilah satu-satunya tempat struktur navigasi dinyatakan.
// tidak-dijalankan
final _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => const LayarDaftarCatatan(),
),
GoRoute(
path: '/tambah',
builder: (context, state) => const LayarTambahCatatan(),
),
],
);Objek router dipasang pada aplikasi melalui MaterialApp.router dengan parameter routerConfig. Bentuk ini menggantikan kombinasi home dan tabel routes, sehingga deklarasi navigasi dan pembacaan URL tidak lagi terpisah.
// tidak-dijalankan
return MaterialApp.router(
title: 'Catatan',
routerConfig: _router,
);Route juga dapat bersarang, yaitu GoRoute memuat daftar routes di dalam dirinya sehingga path anak tersusun di bawah path induk. Hierarki ini berguna ketika satu layar membuka layar-layar turunannya, misalnya layar daftar yang membuka layar detail. Konfigurasi datar pada contoh di atas sudah cukup untuk aplikasi dua layar.
context.go dan context.push#
go_router menyediakan dua fungsi perpindahan pada BuildContext. Fungsi context.go berpindah ke path tujuan dengan membangun ulang stack sesuai konfigurasi, sehingga isi stack sebelumnya tidak dibawa. Fungsi context.push menumpuk layar tujuan di atas layar yang sedang tampil, sebagaimana perilaku Navigator.push.
context.go('/') mengembalikan aplikasi ke layar daftar dengan stack yang bersih:
// tidak-dijalankan
context.go('/');Sementara itu, context.push('/tambah') membuka formulir tambah di atas layar aktif:
// tidak-dijalankan
context.push('/tambah');Pembagian perannya sejajar dengan Navigator, yaitu go untuk perpindahan yang membangun ulang stack seperti kembali ke daftar setelah menyimpan catatan, dan push untuk membuka layar yang masih dapat ditutup kembali. Karena kedua fungsi menggunakan path yang sama, konfigurasi route tidak perlu diubah sama sekali.
Perbedaan lain terletak pada nilai kembaliannya. context.push mengembalikan Future<T?> yang selesai dengan nilai yang dikirim layar tujuan ketika ditutup, sehingga pola menunggu hasil dengan await tetap berlaku. context.go tidak mengembalikan nilai karena tujuannya berpindah, bukan menunggu hasil.
Deep link#
Deep link dimungkinkan oleh pemetaan seluruh layar pada path. URL seperti ‘/catatan/3’ cukup dideklarasikan sebagai pola path dengan parameter, lalu go_router menyusun layarnya. Pada Navigator imperatif, URL semacam ini harus diterjemahkan secara manual menjadi rangkaian push.
// tidak-dijalankan
GoRoute(
path: '/catatan/:id',
builder: (context, state) {
final id = state.pathParameters['id']!;
return LayarDetailCatatan(id: id);
},
),Pola :id menangkap segmen URL dan menyimpannya pada state.pathParameters, sehingga satu deklarasi melayani seluruh id catatan. Konfigurasi yang melayani perpindahan di dalam aplikasi juga melayani deep link, karena keduanya akhirnya berupa URL. Inilah penyederhanaan utama pendekatan deklaratif, yaitu satu tabel untuk semua pintu masuk.
Sumber deep link beragam, antara lain URL dari halaman web, tautan yang dibagikan pengguna, dan notifikasi yang membuka layar tertentu. go_router membaca URL awal saat aplikasi dibuka dan mengikuti perubahan URL pada aplikasi web. Untuk tautan dari luar aplikasi pada perangkat seluler, konfigurasi platform seperti intent filter tetap diperlukan, sedangkan pemetaan URL ke layar tujuan tetap ditangani oleh tabel GoRoute yang sama.
Satu fitur go_router yang berkaitan dengan penyusunan layar adalah shell route. ShellRoute membungkus beberapa route dalam kerangka tampilan bersama, misalnya navigasi bawah yang tetap tampil sementara isi layar berganti, tanpa menambah path baru pada URL. Route anaknya dideklarasikan sebagai daftar di dalam ShellRoute itu sendiri, sehingga hierarki tampilan dan hierarki path tetap dapat dirancang terpisah. Pada tahap ini, mengenali keberadaan fitur ini saja sudah cukup, sedangkan pemanfaatan lengkapnya mengikuti kebutuhan aplikasi.
Ringkasan#
- Navigator imperatif menyebarkan struktur navigasi ke banyak callback, sedangkan go_router menyatakannya secara deklaratif dalam daftar
GoRouteyang memetakan path ke builder. context.gomembangun ulang stack menuju path tujuan, sedangkancontext.pushmenumpuk layar baru di atas layar aktif.- Pola path dengan parameter seperti
:idmembuat satu deklarasi route melayani seluruh deep link yang membawa segmen dinamis. ShellRoutemenyediakan kerangka tampilan bersama untuk beberapa route, misalnya navigasi bawah.
Referensi#
- go_router — pub.dev — Halaman package go_router berisi petunjuk pemasangan dan contoh konfigurasi deklaratif.
- GoRouter class — go_router API docs — Dokumentasi kelas GoRouter beserta daftar GoRoute dan perilaku navigasinya.
- Navigation and routing — Flutter — Panduan resmi navigasi Flutter yang mencakup routing deklaratif dan deep linking.