1. Flutter에 쓰는 Repository
Flutter에서 Repository의 책임은 데이터를 가져오는 클래스
- 휴대폰 디바이스(파일), 휴대폰 DB, Firebase(외부서버), 내 서버, 공공데이터서버
home_repository.dart
class HomeRepository {
const HomeRepository(); // 1개로 관리하기 위한 const
Future<List<int>> getList() async {
List<int> response = await Future.delayed(Duration(seconds: 3), () {
return [1, 2, 3, 4, 5, 6];
});
return response;
}
Future<int> getOne() async {
int response = await Future.delayed(Duration(seconds: 3), () {
return 5;
});
return response;
}
}
Future
- 자바스크립트의 Promise와 유사한 객체
- await Future.delayed
- 통신으로 데이터를 받는 것처럼 테스트하기 위해 3초 뒤에 실행되도록 설정했습니다.
- 비동기로 만들어야 하기 때문에 await를 추가합니다.
- async 함수
- 반환형을 Future<T>로 해야 합니다.
- return이 없으면 Future<void>로 적습니다.
2. Future로 데이터 받기
future_body.dart
class FutureBody extends StatelessWidget {
HomeRepository repo = const HomeRepository();
@override
Widget build(BuildContext context) {
return Column(
children: [
FutureBuilder(
future: repo.getList(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Expanded(
child: ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return ListTile(
leading: Text("${index + 1}"), title: Text("내용"));
}),
);
} else {
// 로딩 중을 시각적으로 보여주는 위젯
return Center(child: CircularProgressIndicator());
}
},
),
],
);
}
}
FutureBuilder
- future: 받을 데이터
- builder: 그림 그릴 내용
- snapshot.hasData → 데이터가 not null일 때 true가 됩니다.
- snapshot.data → 받아온 데이터입니다.
null 처리를 위한 연산자
!
와 ?
!
는 해당 변수가 null이 아니라고 확신할 때 사용합니다.
?
는 해당 변수가 null일 수도 있을 때 사용합니다.
- CircularProgressIndicator
- 로딩 중을 원으로 보여주는 위젯입니다.
3. Riverpod으로 데이터 받기
home_body.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mockapp/home_page_vm.dart';
class HomeBody extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
int? one = ref.watch(homeProvider);
if (one == null) {
return Center(child: CircularProgressIndicator());
} else {
return Column(
children: [
Center(child: Text("$one", style: TextStyle(fontSize: 50))),
],
);
}
}
}
home_page_vm.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mockapp/home_repository.dart';
final homeProvider = NotifierProvider<HomePageVM, int?>(() {
return HomePageVM();
});
class HomePageVM extends Notifier<int?> {
HomeRepository repo = const HomeRepository();
@override
int? build() {
// 상태 초기화 시작
getOne();
// 통신 완료 전 상태 null로 초기화
return null;
}
Future<void> getOne() async {
int one = await repo.getOne();
// View는 상태값을 리턴 받을 필요가 없다. 보고 있기만 하면 된다.(watch)
state = one;
}
}
- async getOne()은 1번은 실행되어야 하므로 View인 ConsumerWidget 보다 ViewModel(VM)에서 초기화 하는 것이 깔끔합니다.
- VM의 장점은 View가 상태값을 받을(return)할 필요가 없습니다.
- WidgetRef.watch(homeProvider) → provider를 통해 VM을 관찰
Share article