@tank/flutter-dev
1.0.0Description
Production Flutter and Dart development patterns. Covers widget architecture, state management (Riverpod, BLoC, Provider), navigation (GoRouter), Dart 3 patterns, layouts, testing, performance profiling, platform channels, and deployment.
Triggered by
flutterdartriverpodblocgo_routerwidget test
Download
Verified
tank install @tank/flutter-devFlutter Development
Core Philosophy
- Composition over inheritance — Build complex UIs by combining small, focused widgets. Extract widgets into separate classes instead of adding parameters to bloated ones.
- Immutable widget tree, mutable state tree — Widgets are throwaway configuration objects. The Element tree persists across frames and drives performance. Understand this distinction to avoid unnecessary rebuilds.
- Push state down, lift state up — Keep state as close to where it is consumed as possible. Lift only when siblings need to share it. Use Riverpod or BLoC for app-level state,
setStatefor ephemeral UI state. - Declarative navigation — Use GoRouter for URL-based, declarative routing. Imperative
Navigator.pushbreaks deep linking, web URLs, and state restoration. - Test the widget, not the framework — Write widget tests that verify behavior, not Flutter internals. Use golden tests for visual regression. Test state management in isolation with unit tests.
Quick-Start: Common Problems
"Which state management should I use?"
| App Type | Recommended |
|---|---|
| New app, any size | Riverpod (NotifierProvider + AsyncNotifierProvider) |
| Existing app with Provider | Migrate incrementally to Riverpod |
| Enterprise, strict event audit | BLoC (event-driven, traceable) |
| Simple prototype / MVP | Riverpod or even plain setState |
| Legacy app with ChangeNotifier | Provider package (maintain, don't rewrite) |
-> See references/state-management.md |
"My widget rebuilds too often"
- Mark constructors
const— enables framework-level rebuild skipping - Extract subtrees that depend on different state into separate widgets
- Use
select(Riverpod) orBlocSelector(BLoC) to watch specific fields - Add
RepaintBoundaryaround expensive paint operations - Profile with Flutter DevTools Widget Rebuild Tracker
-> See
references/performance-deployment.md
"How do I structure navigation with tabs and auth?"
- Use
GoRouterwithStatefulShellRoutefor persistent tab navigation - Add
redirectfor auth guards — check auth state, redirect to/login - Use
ShellRoutefor shared scaffolds (AppBar, Drawer) - Handle deep links by defining path parameters:
/user/:id-> Seereferences/navigation-routing.md
"How do I test a widget that depends on Riverpod/BLoC?"
- Riverpod: wrap with
ProviderScope, override providers with mock values - BLoC: use
BlocProvider.valuewith a mock Bloc/Cubit - Use
pumpWidget+pumpAndSettlefor async rendering - Golden tests:
expectLater(find.byType(X), matchesGoldenFile('x.png'))-> Seereferences/testing.md
"When do I use which Dart pattern?"
- Sealed classes for state unions (loading/data/error)
- Records for returning multiple values without creating a class
- Pattern matching with
switchexpressions for exhaustive handling - Extensions for adding methods to types you do not own
- Freezed for data classes with copyWith, equality, JSON serialization
-> See
references/dart-patterns.md
Decision Trees
Widget Type Selection
| Signal | Widget Type |
|---|---|
| No mutable state, pure UI | StatelessWidget (use const) |
| Ephemeral UI state (animation, form input) | StatefulWidget + setState |
| State shared across subtree without passing props | InheritedWidget (or Riverpod) |
Needs TickerProvider for animations | StatefulWidget with SingleTickerProviderStateMixin |
Layout Widget Selection
| Need | Widget |
|---|---|
| Horizontal or vertical list of children | Row / Column (Flex) |
| Overlapping children | Stack + Positioned |
| Scrollable list of unknown length | ListView.builder |
| Scrollable with mixed content (headers, grids, lists) | CustomScrollView + Sliver* |
| Responsive sizing | LayoutBuilder or MediaQuery |
| Adaptive per platform (Material vs Cupertino) | Platform checks + .adaptive constructors |
Key Type Selection
| Scenario | Key Type |
|---|---|
| Reorder items in a list | ValueKey(item.id) |
| Preserve state when widget moves in tree | GlobalKey (use sparingly) |
| Force rebuild when data identity changes | ValueKey(dataObject) |
| Ensure unique key for generated widgets | UniqueKey() |
Reference Index
| File | Contents |
|---|---|
references/widget-architecture.md | Widget tree, Element tree, BuildContext, Keys, lifecycle methods, composition patterns, RenderObject basics |
references/state-management.md | Riverpod (all provider types, ref patterns, testing), BLoC/Cubit, Provider, selection decision framework |
references/navigation-routing.md | GoRouter setup, ShellRoute, StatefulShellRoute, redirect guards, deep linking, path/query parameters, nested navigation |
references/dart-patterns.md | Null safety, sealed classes, records, pattern matching, extensions, mixins, Freezed, code generation |
references/layouts-responsive.md | Flex system, Stack, Slivers, LayoutBuilder, MediaQuery, breakpoints, Material 3, Cupertino, adaptive design |
references/testing.md | Widget tests, integration tests, golden tests, Riverpod/BLoC test patterns, mocking with Mocktail |
references/performance-deployment.md | DevTools profiling, const optimization, RepaintBoundary, tree shaking, flavors, CI/CD, Fastlane, app store submission |