Flutter
Skill nimadorostkar/Claude-Skills-collection/skills/mobile/flutter
Use when building Flutter applications. Covers widget composition, state management, build-method performance, platform channels, and the rendering behavior behind most Flutter jank.From its SKILL.md
npx -y skills add nimadorostkar/Claude-Skills-collection --skill flutterAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
5.0 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it
Flutter
Purpose
Build Flutter applications whose widget tree rebuilds only where it must. Flutter's performance model is simple and unforgiving: a setState at the top of the tree rebuilds everything below it.
When to Use
- Building or reviewing a Flutter application.
- Choosing and applying a state-management approach.
- Diagnosing jank or excessive rebuilds.
- Integrating with platform-native code.
Capabilities
- Widget composition and the
StatelessWidget/StatefulWidgetboundary. - State management with Riverpod, Bloc, or Provider — and when plain state suffices.
- Build-method optimization:
constconstructors, selective rebuilds, keys. - Async:
Future,Stream,FutureBuilder, and their failure states. - Platform channels for native functionality.
Inputs
- The feature set and target platforms.
- The current state-management approach, if any.
- The jank or rebuild symptom, if debugging.
Outputs
- A widget tree where rebuilds are scoped to what changed.
- State that is testable without a widget tree.
- Async UI that handles loading, error, and empty explicitly.
Workflow
- Compose small widgets — A 300-line
buildmethod rebuilds as one unit. Extracting subtrees into widgets is the primary performance tool in Flutter, not a style preference. - Mark everything possible
const— Aconstwidget is never rebuilt. This is the cheapest optimization available and most codebases leave it on the table. - Scope the rebuild —
Consumer,Selector, or a Riverpod provider that watches one field.setStatein a parent rebuilds every child that is notconst. - Handle all three async states — Loading, error, and data.
FutureBuilderwithout an error branch shows a spinner forever when the request fails. - Profile in profile mode — Debug mode is meaningfully slower and will mislead you in both directions. Use the DevTools timeline on a real device.
Best Practices
constconstructors are the highest-leverage change in most Flutter codebases. Enableprefer_const_constructorsin the linter and fix every warning.- Never build a widget inside a
buildmethod as a function call (Widget _buildHeader()). It defeats the element-tree diffing entirely. Extract a real widget class. - Keys matter when reordering or removing items from a list of stateful widgets. Without them, state attaches to the wrong item.
- Business logic does not belong in a widget. If it cannot be tested without pumping a widget tree, it is in the wrong place.
ListView.builder, notListView(children: [...]), for anything that could be long. The latter builds every child immediately.- An
AnimationControllerwithout adisposeis a leak that ticks forever.
Examples
Scoped rebuild versus a rebuild of everything:
// Costly: setState here rebuilds the whole screen, including the static header
// and the entire list, on every counter tick.
class _DashboardState extends State<Dashboard> {
int _count = 0;
@override
Widget build(BuildContext context) => Column(
children: [
const DashboardHeader(), // const: spared, correctly
OrderList(orders: widget.orders), // not const: rebuilt every tick
Text('$_count'),
ElevatedButton(onPressed: () => setState(() => _count++), child: const Text('+')),
],
);
}
// Better: only the Text listening to the counter rebuilds.
class Dashboard extends ConsumerWidget {
const Dashboard({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) => Column(
children: [
const DashboardHeader(),
const OrderList(),
Consumer(builder: (_, ref, __) => Text('${ref.watch(counterProvider)}')),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).increment(),
child: const Text('+'),
),
],
);
}
Async with every state handled:
switch (ref.watch(ordersProvider)) {
AsyncData(:final value) when value.isEmpty => const EmptyState(),
AsyncData(:final value) => OrderList(orders: value),
AsyncError(:final error) => ErrorState(error: error, onRetry: _retry),
_ => const LoadingSkeleton(),
}
Notes
- Extracting a subtree into a
constwidget removes it from the rebuild path entirely — the framework short-circuits on identity. This is why "just extract widgets" is genuine performance advice in Flutter and not merely tidiness. RepaintBoundaryisolates a subtree's painting. It helps when a small animated element sits inside an expensive static one, and hurts if applied indiscriminately.- Impeller replaced Skia as the default renderer on iOS (and now Android), which eliminates the shader-compilation jank that used to affect first-run animations.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.