[Flutter 교육]
Dart2JS
YAML
복사
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.6
js: ^0.7.1
json_annotation: ^4.9.0
freezed_annotation: ^2.4.4
dev_dependencies:
flutter_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^3.0.0
build_runner: ^2.4.11
freezed: ^2.5.2
json_serializable: ^6.8.0
1. 모델 정의 (user_model.dart)
Dart
복사
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user_model.g.dart';
part 'user_model.freezed.dart';
class User with _$User {
const factory User({
required String id,
required String name,
required int age,
String? email,
([]) List<String> roles,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}
해설
@freezed: 불변 객체를 생성하는 어노테이션
_$User: Freezed가 생성하는 믹스인
const factory: 불변 인스턴스 생성을 위한 팩토리 생성자
@Default([]): 기본값 지정
fromJson: JSON 변환을 위한 팩토리 메서드
2. JavaScript 서비스 정의
Dart
복사
('UserService')
class UserService {
external UserService();
external JSPromise getUserById(String id);
external JSPromise updateUser(JSObject user);
external JSPromise searchUsers(JSObject criteria);
}
해설
@JS(): JavaScript 클래스/함수와 매핑
external: 실제 구현은 JavaScript에 있음을 표시
JSPromise: JavaScript Promise를 나타내는 타입
JSObject: JavaScript 객체를 나타내는 타입
3. 리포지토리 구현
Dart
복사
class UserRepository {
final UserService _service = UserService();
Future<User> getUserById(String id) async {
try {
final JSObject result = await promiseToFuture(_service.getUserById(id));
return User.fromJson(result.dartify() as Map<String, dynamic>);
} catch (e) {
throw Exception('Failed to fetch user: $e');
}
}
해설
promiseToFuture: JS Promise를 Dart Future로 변환
dartify(): JS 객체를 Dart 객체로 변환
as Map<String, dynamic>: 타입 안전성을 위한 캐스팅
에러 처리와 예외 전파
4. 데이터 변환 프로세스
Dart
복사
// JS → Dart
final JSObject result = await promiseToFuture(_service.getUserById(id));
return User.fromJson(result.dartify() as Map<String, dynamic>);
// Dart → JS
final jsUser = user.toJson().jsify();
변환 과정
JavaScript → Dart:
Plain Text
복사
JS Object → JSObject → Dart Map → User 객체
Dart → JavaScript:
Plain Text
복사
User 객체 → Dart Map → JSObject → JS Object
5. 위젯 구현의 주요 포인트
Dart
복사
class _UserManagementWidgetState extends State<UserManagementWidget> {
Future<void> _updateUserAge() async {
if (_selectedUser == null) return;
try {
final updatedUser = await _repository.updateUser(
_selectedUser!.copyWith(age: _selectedUser!.age + 1)
);
setState(() => _selectedUser = updatedUser);
} catch (e) {
// 에러 처리
}
}
해설
copyWith: Freezed가 제공하는 불변 업데이트 메서드
상태 관리: setState를 통한 UI 업데이트
비동기 작업 처리
에러 처리와 사용자 피드백
6. JavaScript 구현
JavaScript
복사
class UserService {
async getUserById(id) {
const mockUser = {
id: id,
name: 'John Doe',
age: 30,
email: 'john@example.com',
roles: ['user', 'admin']
};
return mockUser;
}
해설
비동기 메서드 (async/await 사용)
Promise 반환
모의 데이터 제공
Dart 모델과 일치하는 데이터 구조
7. 주요 기술적 고려사항
타입 안전성
Dart
복사
// 잘못된 방법
final result = await _service.getUserById(id); // 타입 불안전
// 올바른 방법
final JSObject result = await promiseToFuture(_service.getUserById(id));
메모리 관리
Dart
복사
// 메모리 누수 가능성
element.addEventListener('click', allowInterop(handleClick));
// 올바른 방법
final handler = allowInterop(handleClick);
element.addEventListener('click', handler);
element.removeEventListener('click', handler);
성능 최적화
Dart
복사
// 비효율적
for (var user in users) {
final jsUser = user.toJson().jsify(); // 매번 변환
}
// 최적화
final jsUsers = users.map((u) => u.toJson()).toList().jsify(); // 한 번에 변환
8. 베스트 프랙티스
에러 처리
Dart
복사
try {
final result = await promiseToFuture(_service.riskyOperation());
} catch (e) {
if (e is JSError) {
// JavaScript 에러 처리
} else {
// Dart 에러 처리
}
}
타입 체크
Dart
복사
if (result is! JSObject) {
throw TypeError('Expected JSObject');
}
널 체크
Dart
복사
final email = user.email; // Freezed가 제공하는 널 안전성
if (email != null) {
// 안전한 처리
}
9. 디버깅 팁
콘솔 로깅
Dart
복사
('console')
external void log(dynamic message);
// 사용
log(user.toJson()); // JavaScript 콘솔에서 확인
개발자 도구 활용
Dart
복사
// 브레이크포인트 설정 가능한 코드 구조
Future<User> getUserById(String id) async {
final result = await promiseToFuture(_service.getUserById(id));
final json = result.dartify(); // 여기서 중단점 설정
return User.fromJson(json);
}
출처 : https://cheddar-sparrow-aba.notion.site/Dart2JS-13997e0a8ff3807da3c6d76e0011bd4d