More in Flutter & Dart — page 12
Manual JSON Serialization with fromJson/toJson
Manually map your Dart objects to JSON by writing your own `fromJson` and `toJson` methods. This is ideal for simple data models or quick prototypes where code generation is overkill.
JSON in Dart: Using `dart:convert`
`dart:convert` is Dart's built-in translator for JSON. It turns Dart Maps into JSON strings (`jsonEncode`) for APIs and file storage, and parses JSON strings back into Maps (`jsonDecode`). The footgun: `jsonDecode` returns a generic Map, not your custom class.
Dart's `http` Package: Simple Requests vs. Composable Clients
Dart's `http` package simplifies web requests. Use top-level functions like `http.get()` for one-off calls, or a `Client` for persistent connections. Forgetting to call `client.close()` is a common footgun that leaks resources.
Freezed: Immutable State Without Boilerplate
Freezed is a Dart code generator that writes your immutable data classes for you. You define the shape, and it generates constructors, `copyWith`, and equality checks. Use it for model classes and to represent distinct states.

MobX: Automatic UI Updates with Reactive State
MobX automatically wires your reactive data to your Flutter UI, so widgets update when data changes. It's used for state management from simple counters to complex forms. The main footgun is forgetting to wrap all state mutations inside an `Action`.
Redux: Predictable State via a Single Source of Truth
Redux treats app state like a transaction log. All changes are explicit actions processed by pure functions, creating a new, predictable state. It's ideal for complex apps with shared state. The main footgun: putting side effects like API calls in reducers.
GetX State Management: Simplicity Over Boilerplate
GetX simplifies Flutter state management by removing boilerplate and avoiding code generators. It offers both simple manual updates and a reactive style. Use it for rapid development where minimal setup is key.

Riverpod: Compile-Safe, Reactive State Management
Riverpod treats app state like a reactive formula. Define a piece of data once, and Riverpod automatically updates any UI that depends on it. It's ideal for network requests and shared state. Footgun: Watching a provider rebuilds the UI on every change.

Cubit: Simple State Management in Flutter
A Cubit is a simple state manager that exposes functions to directly trigger state changes. It's ideal for managing local UI state, like a counter or form data, without the complexity of events. The footgun is expecting state to update synchronously.
ValueNotifier: Notifies on Replacement, Not Mutation
ValueNotifier is a simple state holder that tells widgets to rebuild when its single value is replaced. It's great for immutable data like a boolean toggle or counter.
Provider: Pass Data Down Your Widget Tree
Think of Provider as a delivery service for your app's data, passing it down the widget tree without sending it through every widget's constructor. It's a lightweight way to manage state. The footgun: never use `.value` to create a new object.
PopScope: Guarding Your Flutter Routes
PopScope acts as a gatekeeper for back navigation in Flutter, letting you intercept and block attempts to leave a screen. Use it to show a confirmation dialog for unsaved changes. Its behavior differs on iOS; the swipe-back gesture won't trigger its callback.
PageRouteBuilder: Custom Routes Without the Boilerplate
PageRouteBuilder creates a custom page route on the fly, skipping the boilerplate of a full subclass. Just provide a `pageBuilder` for the screen's content and a `transitionsBuilder` for a unique animation.
Flutter Hero Animations: Guiding the User's Eye
A Hero animation makes a widget appear to fly from one screen to another, connecting two UIs. It's perfect for transitioning a thumbnail to a detail page, guiding the user's focus. The main footgun is using non-unique tags, which causes animations to fail.
Flutter's Router API: Declarative Navigation
The Router API treats navigation as state. You declare the page stack based on app state, giving you full control over URLs and the back button. This is vital for web/desktop apps but introduces significant boilerplate compared to simple push/pop navigation.
GoRouter: URL-Based Navigation for Flutter Apps
GoRouter treats your app's screens like web pages with URLs. This declarative approach simplifies deep linking and passing data via paths like `/users/123`. The footgun is forgetting its declarative nature and trying to manage state imperatively.
Flutter Named Routes: Navigate with Strings, Not Widgets
Think of named routes as URL paths for your app's screens. Instead of building a screen widget on the spot, you just tell Flutter "go to '/profile'". This is ideal for centralizing navigation in large apps and for enabling deep linking.
Imperative Navigation: Pushing and Popping Screens
Think of app screens as a stack of cards. You `push` a new screen onto the top to show it and `pop` it off to go back. It's ideal for linear flows like list-to-detail. The footgun: popping the last screen closes the app.
MaterialPageRoute: The Page in Your Navigator Stack
Think of Navigator as a stack of screens. MaterialPageRoute wraps your new screen widget, defining its platform-specific transition (slide on iOS, zoom on Android). You use it with `Navigator.push` to show a new screen.
RawKeyboardListener: Deprecated Hardware Key Events in Flutter
This is a deprecated Flutter widget for capturing raw hardware keyboard events, bypassing text input systems. It was for games or custom shortcuts, but the biggest mistake is using it now. Use KeyboardListener instead.