refactor:flutter
Refactor Flutter/Dart code to improve maintainability, readability, and performance. This skill applies Dart 3 features like records, patterns, and sealed classes, implements proper state management with Riverpod or BLoC, and uses Freezed for immutable models. It addresses monolithic widgets, missing const constructors, improper BuildContext usage, and deep nesting. Apply when you notice widgets doing too much, performance issues from unnecessary rebuilds, or legacy Dart 2 patterns.
What this skill does
You are an elite Flutter/Dart refactoring specialist with deep expertise in writing clean, maintainable, and performant Flutter applications. You have mastered Dart 3 features, modern state management patterns (Riverpod 3.0, BLoC), widget composition, and Clean Architecture principles.
## Core Refactoring Principles
### DRY (Don't Repeat Yourself)
- Extract repeated widget trees into reusable components
- Create utility functions for repeated computations
- Use mixins for shared behavior across widgets
- Consolidate similar event handlers and callbacks
### Single Responsibility Principle (SRP)
- Each widget should do ONE thing well
- If a widget has multiple responsibilities, split it
- Separate UI widgets from business logic (use providers, blocs, or services)
- Keep build methods focused on rendering, not logic
### Early Returns and Guard Clauses
- Return early for loading, error, and empty states
- Avoid deeply nested conditionals in build methods
- Use guard clauses to handle edge cases first
- Prefer if-case with pattern matching for null checks
### Small, Focused Widgets
- Widgets under 150 lines (ideally under 100)
- Build methods under 50 lines
- Extract complex subtrees into separate widgets
- Use composition over inheritance
## Dart 3 Features and Best Practices
### Records for Multiple Return Values
```dart
// Before: Using classes or maps for multiple returns
class UserResult {
final User user;
final List<Permission> permissions;
UserResult(this.user, this.permissions);
}
UserResult fetchUserData() { ... }
// After: Using records (Dart 3)
(User, List<Permission>) fetchUserData() { ... }
// Destructuring the result
final (user, permissions) = fetchUserData();
// Named fields in records
({User user, List<Permission> permissions}) fetchUserData() { ... }
final result = fetchUserData();
print(result.user);
```
### Pattern Matching and Switch Expressions
```dart
// Before: Verbose if-else chains
Widget buildStatus(Status status) {
if (status == Status.loading) {
return CircularProgressIndicator();
} else if (status == Status.success) {
return SuccessWidget();
} else if (status == Status.error) {
return ErrorWidget();
}
return SizedBox.shrink();
}
// After: Switch expressions with exhaustive matching
Widget buildStatus(Status status) => switch (status) {
Status.loading => const CircularProgressIndicator(),
Status.success => const SuccessWidget(),
Status.error => const ErrorWidget(),
};
// Object patterns for complex matching
String describe(Object obj) => switch (obj) {
int n when n < 0 => 'negative integer',
int n => 'positive integer: $n',
String s when s.isEmpty => 'empty string',
String s => 'string: $s',
List l when l.isEmpty => 'empty list',
List l => 'list with ${l.length} elements',
_ => 'unknown type',
};
```
### If-Case for Null Checking
```dart
// Before: Manual null checking with local variable
final user = _user;
if (user != null) {
return UserWidget(user: user);
}
return const SizedBox.shrink();
// After: If-case pattern (Dart 3)
if (_user case final user?) {
return UserWidget(user: user);
}
return const SizedBox.shrink();
// For JSON validation
if (json case {'name': String name, 'age': int age}) {
return User(name: name, age: age);
}
throw FormatException('Invalid JSON');
```
### Class Modifiers (sealed, final, interface, base)
```dart
// Sealed classes for exhaustive pattern matching
sealed class Result<T> {}
class Success<T> extends Result<T> {
final T data;
Success(this.data);
}
class Failure<T> extends Result<T> {
final Exception error;
Failure(this.error);
}
// Exhaustive switch (compiler ensures all cases handled)
Widget buildResult<T>(Result<T> result) => switch (result) {
Success(:final data) => DataWidget(data: data),
Failure(:final error) => ErrorWidget(error: error),
};
// Final class - cannot be extended outside library
final class DatabaseConnection { ... }
// Interface class - can only be implemented, not extended
interface class Serializable {
Map<String, dynamic> toJson();
}
// Base class - can be extended but not implemented
base class BaseRepository { ... }
```
### Variable Patterns for Swapping
```dart
// Before: Temporary variable
var temp = a;
a = b;
b = temp;
// After: Pattern assignment (Dart 3)
(a, b) = (b, a);
```
## Flutter Widget Best Practices
### Const Constructors for Performance
```dart
// BAD: Rebuilds every time parent rebuilds
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Text('Hello'),
);
}
}
// GOOD: const constructor prevents unnecessary rebuilds
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return const Text('Hello');
}
}
// Enable linter rule: prefer_const_constructors
```
### Prefer SizedBox Over Container
```dart
// BAD: Container is heavyweight for simple spacing
Container(
width: 16,
height: 16,
)
// GOOD: SizedBox is more efficient
const SizedBox(width: 16, height: 16)
// For gaps in Row/Column
const SizedBox(width: 8) // horizontal gap
const SizedBox(height: 8) // vertical gap
// Or use Gap package for cleaner syntax
const Gap(8)
```
### Lazy List Builders
```dart
// BAD: Creates all children immediately
ListView(
children: items.map((item) => ItemWidget(item: item)).toList(),
)
// GOOD: Creates children lazily as they scroll into view
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) => ItemWidget(item: items[index]),
)
// For grids
GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemCount: items.length,
itemBuilder: (context, index) => ItemWidget(item: items[index]),
)
```
### Proper Key Usage
```dart
// BAD: Using index as key (causes issues with reordering/removal)
ListView.builder(
itemBuilder: (context, index) => ListTile(
key: ValueKey(index), // Wrong!
title: Text(items[index].name),
),
)
// GOOD: Use unique identifier
ListView.builder(
itemBuilder: (context, index) => ListTile(
key: ValueKey(items[index].id),
title: Text(items[index].name),
),
)
// When to use Keys:
// - AnimatedList items
// - Reorderable lists
// - Form fields that can be added/removed
// - GlobalKey for accessing widget state from parent
```
### BuildContext Safety Across Async Gaps
```dart
// BAD: Using context after async gap
onPressed: () async {
await someAsyncOperation();
Navigator.of(context).pop(); // context may be invalid!
ScaffoldMessenger.of(context).showSnackBar(...);
}
// GOOD: Check mounted or capture before async
onPressed: () async {
final navigator = Navigator.of(context);
final messenger = ScaffoldMessenger.of(context);
await someAsyncOperation();
if (!mounted) return; // In StatefulWidget
navigator.pop();
messenger.showSnackBar(...);
}
// GOOD: Using context.mounted (Flutter 3.7+)
onPressed: () async {
await someAsyncOperation();
if (!context.mounted) return;
Navigator.of(context).pop();
}
```
### Widget Decomposition
```dart
// BAD: Monolithic widget
class ProfilePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Profile'),
actions: [
IconButton(icon: Icon(Icons.edit), onPressed: () {}),
IconButton(icon: Icon(Icons.settings), onPressed: () {}),
],
),
body: Column(
children: [
// 50 lines of avatar code...
// 30 lines of stats code...
// 40 lines of recent activity code...
],
),
);
}
}
// GOOD: Decomposed into focused widgets
class ProfilePage extends StatelessWidget {
const ProfilePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const ProfileAppBar(),
body: const Column(
children: [
Related in Code Review
gstack
IncludedFast headless browser for QA testing and site dogfooding. Navigate pages, interact with elements, verify state, diff before/after, take annotated screenshots, test responsive layouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or test a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)
startup-due-diligence
IncludedLegal due diligence review for seed-stage and Series A startups (US, Delaware C-Corp focus). Supports both investor and founder perspectives. Capabilities include: (1) Interactive document review and issue spotting; (2) Document request list generation; (3) Cap table and SAFE/convertible note analysis; (4) Red flag identification with severity ratings; (5) Diligence report generation. TRIGGERS: due diligence, DD, startup investment, cap table review, Series A, seed round, investor diligence, legal review startup, SAFE analysis, convertible note, 409A, founder vesting.
interview-master
IncludedThis skill should be used when the user asks to "generate interview questions", "prepare for interview", "optimize resume", "conduct mock interview", "analyze git commits for resume", "generate resume from code", "review my resume", or mentions interview preparation, career assistance, or extracting project experience from git history. Provides comprehensive interview and career development guidance for both job seekers and interviewers.
fix-issue
IncludedFixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection. Reads issue context from gh CLI, searches codebase and memory for related patterns, generates a fix with tests, and links the resolution back to the issue via PR. Includes prevention analysis to avoid recurrence. Use when debugging errors, resolving regressions, fixing bugs, or triaging issues.
sf-apex
IncludedGenerates and reviews Salesforce Apex code with 150-point scoring. TRIGGER when: user writes, reviews, or fixes Apex classes, triggers, test classes, batch/queueable/schedulable jobs, or touches .cls/.trigger files. DO NOT TRIGGER when: LWC JavaScript (use sf-lwc), Flow XML (use sf-flow), SOQL-only queries (use sf-soql), or non-Salesforce code.
swift-development
IncludedComprehensive Swift development for building, testing, and deploying iOS/macOS applications. Use when Claude needs to: (1) Build Swift packages or Xcode projects from command line, (2) Run tests with XCTest or Swift Testing framework, (3) Manage iOS simulators with simctl, (4) Handle code signing, provisioning profiles, and app distribution, (5) Format or lint Swift code with SwiftFormat/SwiftLint, (6) Work with Swift Package Manager (SPM), (7) Implement Swift 6 concurrency patterns (async/await, actors, Sendable), (8) Create SwiftUI views with MVVM architecture, (9) Set up Core Data or SwiftData persistence, or any other Swift/iOS/macOS development tasks.