# Flutter AI rules — state, routing and data State management, data flow, routing, JSON serialization and logging. _Verbatim from [flutter/flutter docs/rules/rules.md](https://github.com/flutter/flutter/blob/main/docs/rules/rules.md), split across four files only to keep each under the repo's 250-line cap. Re-fetch periodically to stay current; do not hand-edit._ #### State Management * **Built-in Solutions:** Prefer Flutter's built-in state management solutions. Do not use a third-party package unless explicitly requested. * **Streams:** Use `Streams` and `StreamBuilder` for handling a sequence of asynchronous events. * **Futures:** Use `Futures` and `FutureBuilder` for handling a single asynchronous operation that will complete in the future. * **ValueNotifier:** Use `ValueNotifier` with `ValueListenableBuilder` for simple, local state that involves a single value. ```dart // Define a ValueNotifier to hold the state. final ValueNotifier _counter = ValueNotifier(0); // Use ValueListenableBuilder to listen and rebuild. ValueListenableBuilder( valueListenable: _counter, builder: (context, value, child) { return Text('Count: $value'); }, ); ``` * **ChangeNotifier:** For state that is more complex or shared across multiple widgets, use `ChangeNotifier`. * **ListenableBuilder:** Use `ListenableBuilder` to listen to changes from a `ChangeNotifier` or other `Listenable`. * **MVVM:** When a more robust solution is needed, structure the app using the Model-View-ViewModel (MVVM) pattern. * **Dependency Injection:** Use simple manual constructor dependency injection to make a class's dependencies explicit in its API, and to manage dependencies between different layers of the application. * **Provider:** If a dependency injection solution beyond manual constructor injection is explicitly requested, `provider` can be used to make services, repositories, or complex state objects available to the UI layer without tight coupling (note: this document generally defaults against third-party packages for state management unless explicitly requested). #### Data Flow * **Data Structures:** Define data structures (classes) to represent the data used in the application. * **Data Abstraction:** Abstract data sources (e.g., API calls, database operations) using Repositories/Services to promote testability. #### Routing * **GoRouter:** Use the `go_router` package for declarative navigation, deep linking, and web support. * **GoRouter Setup:** To use `go_router`, first add it to your `pubspec.yaml` using the `pub` tool's `add` command. ```dart // 1. Add the dependency // flutter pub add go_router // 2. Configure the router final GoRouter _router = GoRouter( routes: [ GoRoute( path: '/', builder: (context, state) => const HomeScreen(), routes: [ GoRoute( path: 'details/:id', // Route with a path parameter builder: (context, state) { final String id = state.pathParameters['id']!; return DetailScreen(id: id); }, ), ], ), ], ); // 3. Use it in your MaterialApp MaterialApp.router( routerConfig: _router, ); ``` * **Authentication Redirects:** Configure `go_router`'s `redirect` property to handle authentication flows, ensuring users are redirected to the login screen when unauthorized, and back to their intended destination after successful login. * **Navigator:** Use the built-in `Navigator` for short-lived screens that do not need to be deep-linkable, such as dialogs or temporary views. ```dart // Push a new screen onto the stack Navigator.push( context, MaterialPageRoute(builder: (context) => const DetailsScreen()), ); // Pop the current screen to go back Navigator.pop(context); ``` #### Data Handling & Serialization * **JSON Serialization:** Use `json_serializable` and `json_annotation` for parsing and encoding JSON data. * **Field Renaming:** When encoding data, use `fieldRename: FieldRename.snake` to convert Dart's camelCase fields to snake_case JSON keys. ```dart // In your model file import 'package:json_annotation/json_annotation.dart'; part 'user.g.dart'; @JsonSerializable(fieldRename: FieldRename.snake) class User { final String firstName; final String lastName; User({required this.firstName, required this.lastName}); factory User.fromJson(Map json) => _$UserFromJson(json); Map toJson() => _$UserToJson(this); } ``` #### Logging * **Structured Logging:** Use the `log` function from `dart:developer` for structured logging that integrates with Dart DevTools. ```dart import 'dart:developer' as developer; // For simple messages developer.log('User logged in successfully.'); // For structured error logging try { // ... code that might fail } catch (e, s) { developer.log( 'Failed to fetch data', name: 'myapp.network', level: 1000, // SEVERE error: e, stackTrace: s, ); } ``` ### Code Generation