Skip to content
Back to skills

Flutter Helper

ASecurity

Aide au développement Flutter/Dart avec bonnes pratiques, patterns, snippets copiables et diagnostics d'erreurs. Se déclenche avec "Flutter", "Dart", "Widget", "BLoC", "Riverpod", "Provider", "pub.dev", "MaterialApp", "flutter build". Also triggers on "Flutter app", "Dart widget", "Flutter state management".

  • 27 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 18, 2026
ai-agentsgobashawstestingapiperformance

Works with

  • api

Security analysis

A100/100

Scanned October 18, 2026

npx -y skills add khalilbenaz/claude-skills-collection --skill flutter-helper --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Flutter Helper?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Flutter Helper
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/khalilbenaz-flutter-helper/badge)](https://www.skillsdirectory.com/skills/khalilbenaz-flutter-helper)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: flutter-helper
description: Aide au développement Flutter/Dart avec bonnes pratiques, patterns, snippets copiables et diagnostics d'erreurs. Se déclenche avec "Flutter", "Dart", "Widget", "BLoC", "Riverpod", "Provider", "pub.dev", "MaterialApp", "flutter build". Also triggers on "Flutter app", "Dart widget", "Flutter state management".
---

# Flutter Helper

## 1. Diagnostic initial

Avant tout, collecter :
- `flutter --version` → version SDK (cible : Flutter 3.22+, Dart 3.4+)
- `flutter doctor -v` → chaîne outils (Xcode, Android SDK, etc.)
- Message d'erreur complet (stack trace si disponible)
- Plateforme cible (Android / iOS / Web / Desktop)

---

## 2. Structure projet

**Feature-first** (projets moyens/grands) :
```
lib/
  features/
    auth/
      data/        # repositories, data sources, models
      domain/      # entities, use cases
      presentation/ # pages, widgets, controllers
  core/            # DI, router, theme, utils
  main.dart
```

**Layer-first** (petits projets ou prototypes) :
```
lib/
  data/ domain/ presentation/
  main.dart
```

Critère de choix : si > 3 features ou > 2 devs → feature-first obligatoire.

---

## 3. State management — décision

| Taille projet | Solution recommandée | Quand éviter |
|---|---|---|
| Prototype / très petit | `Provider` | > 3 features |
| Moyen | **Riverpod 2.x** | jamais — convient toujours |
| Grande logique métier | **BLoC/Cubit** | sur-architecture sur petits cas |
| Full-stack léger | `GetX` | maintainability sacrifiée |

**Riverpod — pattern minimal fonctionnel :**
```dart
// counter_provider.dart
final counterProvider = StateNotifierProvider<CounterNotifier, int>(
  (ref) => CounterNotifier(),
);

class CounterNotifier extends StateNotifier<int> {
  CounterNotifier() : super(0);
  void increment() => state++;
}

// widget
class CounterPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Text('$count');
  }
}
```

**Cubit — pattern minimal :**
```dart
class AuthCubit extends Cubit<AuthState> {
  AuthCubit(this._repo) : super(AuthInitial());
  final AuthRepository _repo;

  Future<void> login(String email, String password) async {
    emit(AuthLoading());
    try {
      final user = await _repo.login(email, password);
      emit(AuthSuccess(user));
    } catch (e) {
      emit(AuthError(e.toString()));
    }
  }
}
```

---

## 4. Widgets — règles de performance

```dart
// ✅ Bon : const constructor évite le rebuild
const MyCard({super.key, required this.title});

// ✅ Isoler le Consumer au plus proche de la donnée
Consumer<CartModel>(
  builder: (_, cart, __) => Text('${cart.itemCount}'),
);

// ❌ Mauvais : Consumer sur tout l'arbre
Consumer<CartModel>(
  builder: (_, cart, __) => Scaffold(...),  // rebuild = toute la page
);

// ✅ ListView.builder pour listes longues
ListView.builder(
  itemCount: items.length,
  itemBuilder: (_, i) => ItemTile(item: items[i]),
);
```

Règle : **jamais de logique métier dans `build()`** — uniquement présentation.

---

## 5. Navigation — GoRouter (recommandé 2025+)

```yaml
# pubspec.yaml
dependencies:
  go_router: ^14.0.0
```

```dart
final router = GoRouter(
  initialLocation: '/home',
  redirect: (context, state) {
    final loggedIn = ref.read(authProvider).isLoggedIn;
    if (!loggedIn && state.matchedLocation != '/login') return '/login';
    return null;
  },
  routes: [
    GoRoute(path: '/login', builder: (_, __) => const LoginPage()),
    GoRoute(
      path: '/home',
      builder: (_, __) => const HomePage(),
      routes: [
        GoRoute(path: 'detail/:id', builder: (_, s) => DetailPage(id: s.pathParameters['id']!)),
      ],
    ),
  ],
);

// Navigation
context.go('/home/detail/42');
context.push('/home/detail/42');  // ajoute au back stack
```

---

## 6. Networking + modèles

```yaml
dependencies:
  dio: ^5.4.0
  retrofit: ^4.1.0
  freezed_annotation: ^2.4.1
  json_annotation: ^4.9.0
dev_dependencies:
  build_runner: ^2.4.9
  freezed: ^2.4.7
  json_serializable: ^6.7.1
  retrofit_generator: ^8.1.0
```

```dart
// model généré via freezed
@freezed
class User with _$User {
  const factory User({
    required int id,
    required String name,
    String? avatar,
  }) = _User;
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}

// génération : flutter pub run build_runner build --delete-conflicting-outputs
```

Intercepteur Dio pour token :
```dart
dio.interceptors.add(InterceptorsWrapper(
  onRequest: (options, handler) {
    options.headers['Authorization'] = 'Bearer $token';
    handler.next(options);
  },
));
```

---

## 7. Testing

```dart
// Widget test
testWidgets('affiche le titre', (tester) async {
  await tester.pumpWidget(const MaterialApp(home: MyWidget(title: 'Test')));
  expect(find.text('Test'), findsOneWidget);
});

// BLoC/Cubit test
blocTest<AuthCubit, AuthState>(
  'émet AuthSuccess après login réussi',
  build: () => AuthCubit(mockRepo),
  act: (c) => c.login('u@test.com', 'pass'),
  expect: () => [isA<AuthLoading>(), isA<AuthSuccess>()],
);
```

Commandes utiles :
```bash
flutter test                          # tous les tests
flutter test --coverage               # avec couverture
genhtml coverage/lcov.info -o cov_html # rapport HTML
flutter test integration_test/        # tests d'intégration
```

---

## 8. Performance — checklist

- [ ] `const` sur tous les constructeurs éligibles
- [ ] `ListView.builder` / `SliverList` pour listes > 20 items
- [ ] `RepaintBoundary` autour des animations complexes
- [ ] Traitements lourds dans `Isolate` ou `compute()`
- [ ] `cached_network_image` pour images distantes
- [ ] Profiler avec **Flutter DevTools** → onglet Performance (frame budget 16ms)

```dart
// compute() = Isolate simplifié
final result = await compute(parseJsonHeavy, rawString);
```

---

## 9. Build & déploiement

```bash
# flavors via dart-define
flutter run --dart-define=ENV=staging
flutter build apk --dart-define=ENV=prod --release

# APK split par ABI (taille réduite)
flutter build apk --split-per-abi

# iOS archive
flutter build ipa --release

# Versions automatiques
flutter pub version          # avec package cider
```

Flavors dans le code :
```dart
const env = String.fromEnvironment('ENV', defaultValue: 'dev');
```

---

## 10. Anti-patterns / pièges à éviter

| Piège | Solution |
|---|---|
| `setState` dans un `StatelessWidget` | Passer à `StatefulWidget` ou state manager |
| `BuildContext` utilisé après `await` | Vérifier `mounted` avant toute opération post-await |
| Appels API dans `build()` | Déplacer dans `initState` ou un provider |
| `Image.network()` sans cache | Utiliser `CachedNetworkImage` |
| Packages abandonnés (vérifier pub.dev) | Filtrer par "Likes > 100" et "Maintained" |
| `print()` en production | Remplacer par `debugPrint()` ou logger package |
| Nested `Scaffold` | Un seul `Scaffold` par route |

```dart
// ✅ Vérification mounted après async
Future<void> fetchData() async {
  final data = await api.get();
  if (!mounted) return;          // évite memory leak / crash
  setState(() => _data = data);
}
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.