[G1-Sync] Manual knowledge update

This commit is contained in:
Antigravity Agent
2026-05-09 21:08:02 +09:00
parent f0befc887a
commit 93ec7e9056
363 changed files with 68333 additions and 64 deletions
@@ -0,0 +1,323 @@
---
id: mobile-flutter-patterns
title: Flutter — Widget / State / Riverpod
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [mobile, flutter, dart, vibe-coding]
tech_stack: { language: "Dart / Flutter", applicable_to: ["iOS", "Android", "Web", "Desktop"] }
applied_in: []
aliases: [Flutter, Dart, Riverpod, Bloc, GoRouter, Material 3]
---
# Flutter
> Google 의 cross-platform UI. **단일 codebase → iOS / Android / Web / Desktop**. **Skia / Impeller 가 그림 — native 만큼 빠름**. Material 3 / Cupertino UI built-in.
## 📖 핵심 개념
- Widget: 모든 거. immutable.
- State: StatefulWidget 의 mutable.
- Riverpod / Bloc: state management.
- Hot reload: 변경 즉시 반영.
## 💻 코드 패턴
### 기본 widget
```dart
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.blue),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(child: Text('$_count', style: Theme.of(context).textTheme.displayLarge)),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => _count++),
child: const Icon(Icons.add),
),
);
}
}
```
### Layout
```dart
Scaffold(
body: SafeArea(
child: Column(
children: [
const Text('Header'),
Expanded(
child: ListView.builder(
itemCount: items.length,
itemBuilder: (ctx, i) => ListTile(
title: Text(items[i].name),
onTap: () => Navigator.push(ctx, MaterialPageRoute(builder: (_) => DetailPage(items[i]))),
),
),
),
],
),
),
)
```
### Riverpod (state management)
```yaml
# pubspec.yaml
dependencies:
flutter_riverpod: ^2.4.0
riverpod_annotation: ^2.3.0
```
```dart
@riverpod
class Counter extends _$Counter {
@override
int build() => 0;
void increment() => state++;
}
@riverpod
Future<List<User>> users(UsersRef ref) async {
final dio = ref.watch(dioProvider);
final r = await dio.get('/users');
return (r.data as List).map((j) => User.fromJson(j)).toList();
}
// Widget
class CounterPage extends ConsumerWidget {
@override
Widget build(BuildContext ctx, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Column(
children: [
Text('$count'),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).increment(),
child: const Text('+'),
),
],
);
}
}
```
### AsyncValue (network state)
```dart
class UsersPage extends ConsumerWidget {
@override
Widget build(BuildContext ctx, WidgetRef ref) {
final asyncUsers = ref.watch(usersProvider);
return asyncUsers.when(
data: (users) => ListView.builder(...),
loading: () => const CircularProgressIndicator(),
error: (e, _) => Text('Error: $e'),
);
}
}
```
### GoRouter (navigation)
```dart
final router = GoRouter(
routes: [
GoRoute(path: '/', builder: (_, __) => const HomePage()),
GoRoute(
path: '/user/:id',
builder: (_, state) => UserPage(id: state.pathParameters['id']!),
),
],
);
MaterialApp.router(routerConfig: router, ...);
```
### Network (Dio)
```dart
final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
options.headers['Authorization'] = 'Bearer $token';
handler.next(options);
},
onError: (e, handler) {
if (e.response?.statusCode == 401) refreshAuth();
handler.next(e);
},
));
final r = await dio.get('/users/$id');
final user = User.fromJson(r.data);
```
### Freezed (immutable model)
```dart
@freezed
class User with _$User {
const factory User({
required String id,
required String email,
String? name,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}
```
```bash
dart run build_runner build # 코드 generate
```
### Async / await
```dart
Future<void> _load() async {
setState(() => _loading = true);
try {
final users = await api.fetchUsers();
setState(() => _users = users);
} catch (e) {
showError(e.toString());
} finally {
setState(() => _loading = false);
}
}
```
### 새 architecture (riverpod hooks 같이)
```dart
class HomePage extends HookConsumerWidget {
@override
Widget build(BuildContext ctx, WidgetRef ref) {
final controller = useTextEditingController();
final search = useState('');
final users = ref.watch(searchUsersProvider(search.value));
return Column(
children: [
TextField(controller: controller, onChanged: (v) => search.value = v),
users.when(...),
],
);
}
}
```
### Test
```dart
testWidgets('counter increments', (tester) async {
await tester.pumpWidget(const MyApp());
expect(find.text('0'), findsOneWidget);
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text('1'), findsOneWidget);
});
// Riverpod
test('counter', () {
final container = ProviderContainer();
expect(container.read(counterProvider), 0);
container.read(counterProvider.notifier).increment();
expect(container.read(counterProvider), 1);
});
```
### Build / release
```bash
# iOS
flutter build ipa --release
# Android
flutter build appbundle --release
# Web
flutter build web --release
# Desktop
flutter build macos --release
flutter build windows --release
```
### Performance
- `const` constructor 사용 (rebuild skip).
- Widget trees 작게 + split.
- `RepaintBoundary` 큰 widget 분리.
- Image cache (cached_network_image).
- Lists = ListView.builder (lazy).
### vs React Native / Native
```
Flutter:
+ 빠름 (Skia compile)
+ 같은 UI 모든 platform
+ Hot reload 강력
- Dart language (학습)
- Native 통합 = platform channel
- Bundle 큼 (~5-15MB)
React Native:
+ JS / TS 친숙
+ 큰 ecosystem
- JS bridge / new arch 학습
- Native UI 위주
Native:
+ Best UX / performance
- 두 번 개발
```
## 🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| Cross-platform + 일관 UI | Flutter |
| 작은 팀 / 빠른 MVP | Flutter / RN |
| Native UX strict | Native |
| Web 도 같이 | Flutter Web |
| Desktop 도 같이 | Flutter |
| 큰 native ecosystem 의존 | Native / RN |
## ❌ 안티패턴
- **`const` 안 씀**: 매 rebuild.
- **거대 build method**: 분리.
- **setState 큰 tree**: 작은 stateful widget.
- **Provider 너무 많음 (각 var)**: combine.
- **Dio interceptor 안 + auth 매번**: 통일.
- **Async/await 없는 callback hell**: future 변환.
- **Native channel 직접 (필요 시)**: package 사용 / pigeon.
## 🤖 LLM 활용 힌트
- Riverpod + Freezed + GoRouter + Dio = 표준 stack.
- AsyncValue.when 으로 loading/error 깔끔.
- const constructor + ListView.builder.
## 🔗 관련 문서
- [[Mobile_KMP_Compose]]
- [[React_Native_Bridge_Performance]]
- [[Android_Compose_State_Hoisting]]