simple_routes 2.1.0+beta.1
simple_routes: ^2.1.0+beta.1 copied to clipboard
Simple, declarative route and navigation management for go_router.
Simple Routes #
Simple, declarative route and navigation management for go_router.
simple_routes is a companion package to GoRouter that provides a simple, declarative way to define your app's routes. By using simple_routes, you can eliminate magic strings, simplify your route definitions, and enforce type-safe routing requirements.
Features #
- Code Generation: Automatically generate route and data classes from simple abstract blueprints.
- Type Safety: Enforce required path parameters, query parameters, and extra data at compile time.
- Declarative Hierarchy: Define child routes easily and inherit path parameters automatically.
- Explicit Data Extraction: Extract route data from
GoRouterStateusing generated factory constructors. - Advanced Matching: Check if a route is currently active, a parent of the current route, or an exact match.
Table of Contents #
Getting Started #
Add simple_routes and simple_routes_annotations to your pubspec.yaml:
dependencies:
go_router: [latest]
simple_routes: [latest]
simple_routes_annotations: [latest]
Add simple_routes_generator and build_runner to your dev_dependencies:
dev_dependencies:
build_runner: [latest]
simple_routes_generator: [latest]
Usage #
Code Generation (Recommended) #
Code generation is the recommended way to use simple_routes. It automates the creation of route and data classes, ensures type safety, and simplifies data extraction.
Defining Routes
Define your routes as "blueprint" classes and annotate them with @Route. These are simple abstract classes used as metadata for the generator.
import 'package:simple_routes/simple_routes.dart';
part 'routes.g.dart';
@Route('/')
abstract class Root {}
@Route('dashboard')
abstract class Dashboard {}
Routes with Parameters
For routes with path parameters, define them as abstract getters and annotate them with @Path().
@Route('profile/:userId')
abstract class Profile {
// If the name of the field matches the path segment, you can omit the name.
// Otherwise, you must provide the name.
// Example:
// @Path('userId')
// String get id;
@Path()
String get userId;
}
Child Routes and Inheritance
To define a child route, use the parent property in the @Route annotation. Child routes automatically inherit all path parameters from their ancestors.
@Route('edit', parent: Profile)
abstract class ProfileEdit {} // Inherits 'userId' from Profile
Query Parameters
Use the @Query() annotation to define query parameters.
@Route('search')
abstract class Search {
@Query('q')
String get query;
}
Extra Data
Use the @Extra() annotation to pass complex objects via GoRouter's extra property.
@Route('details')
abstract class Details {
@Extra()
MyData get data;
}
Generating Code
Run the build runner to generate your route classes:
dart run build_runner build
The generator creates a [ClassName]Route class for navigation and a [ClassName]RouteData class for holding parameters.
Manual Route Definition #
If you prefer not to use code generation, you can define your routes manually by extending SimpleRoute or SimpleDataRoute.
class UserRoute extends SimpleDataRoute<UserRouteData> {
const UserRoute() : super('users/:userId');
}
class UserRouteData extends SimpleRouteData {
const UserRouteData({required this.userId});
final String userId;
@override
Map<String, String> get parameters => {'userId': userId};
}
Navigation #
Use the go and push methods on your route classes to initiate navigation.
// Simple route
const DashboardRoute().go(context);
// Route with data
const ProfileRoute().go(
context,
data: const ProfileRouteData(id: '123'),
);
Advanced Usage #
Extracting Data #
Each generated RouteData class includes a fromState factory constructor for easy extraction from GoRouterState:
builder: (context, state) {
final data = ProfileRouteData.fromState(state);
return ProfileScreen(userId: data.id);
}
Route Matching #
Use the following methods to determine the current navigation state:
isCurrentRoute(state): Returnstrueif the route is an exact match for the current location.isParentRoute(state): Returnstrueif the route is a parent of the current location.isActive(state): Returnstrueif the route is either the current route or a parent.
final state = GoRouterState.of(context);
if (const ProfileRoute().isActive(state)) {
// Profile or a child of Profile is active
}