라이브러리 세팅
// 터미널 명령어
flutter pub add dio // dio
flutter pub add logger // test용 로거
flutter pub add flutter_riverpod // riverpod
1. Dio 세팅
http_util.dart
import 'package:dio/dio.dart';
final Dio dio = Dio(
BaseOptions(
// fake api
baseUrl: "https://jsonplaceholder.typicode.com",
headers: {
"Content-Type": "application/json"
}
)
);
- baseUrl
- Dio 관련된 메서드 작성 시 url 주소를 적을 때 baseUrl을 생략해도 됩니다.
- headers
- 마임 타입 설정
2. Repository
post_repository.dart
// SRP : 데이터를 가져오는 곳
class PostRepository {
const PostRepository();
Future<Post> getPost() async {
// Future<Response<T>> 반환
Response response = await dio.get("/posts/1");
// dio 설정 상 Map으로 준다.
Map<String, dynamic> mapData = response.data;
// logger 라이브러리 사용. d는 debug
Logger().d(mapData);
// Map에서 Post로
return Post.fromMap(mapData);
}
}
- getPost() → 비동기 함수로 작성
- await dio.get("/posts/1")
- “baseUrl + /posts/1” 주소로 get 요청을 합니다.
- 반환값은 Map으로 줍니다.
{
"userId": 1,
"id": 1,
"title": "타이틀"
"body": "내용"
}
- Post.fromMap(mapData)
- post_page_vm.dart에 정의되어 있는 Post class의 메서드입니다.
- Map<String, dynamic>을 Post 객체로 변환합니다.
3. 리포지토리 테스트
post_repository_test.dart
import 'package:mockapp/post_repository.dart';
void main() async {
PostRepository repo = PostRepository();
await repo.getPost();
}
- 비동기 함수로 작성해야 로그가 제대로 뜹니다.
- repo.getPost() 로 쓸 경우 getPost()가 비동기 함수이기 때문에 이 부분 코드를 넘어서 계속 진행이 되므로 main이 꺼지기 때문입니다.
4. ViewModel
post_page_vm.dart
class Post {
int userId;
int id;
String title;
String body;
Post(this.userId, this.id, this.title, this.body);
// 이름있는 생성자, Map을 Post로
Post.fromMap(Map<String, dynamic> map) :
userId = map["userId"],
id = map["id"],
title = map["title"],
body = map["body"];
}
final postProvider = NotifierProvider<PostPageVM, Post?>(() {
return PostPageVM();
});
class PostPageVM extends Notifier<Post?> {
PostRepository repo = const PostRepository();
@override
Post? build() {
// 상태 초기화 시작
init();
// 상태 null 초기화
return null;
}
Future<void> init() async {
Post post = await repo.getPost();
state = post;
}
}
- Post.fromMap(Map<String, dynamic> map)
:
- 이름이 있는 생성자입니다.
- Map<String, dynamic>을 받아서 Post 객체로 변환합니다.
- state
- 상태를 나타내는 변수 이름입니다.
5. View
post_body.dart
class PostBody extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
Post? model = ref.watch(postProvider);
if (model == null) {
return Center(child: CircularProgressIndicator());
} else {
return Column(
children: [
Text("id : ${model.id}"),
Text("userId : ${model.userId}"),
Text("title : ${model.title}"),
Text("body : ${model.body}"),
],
);
}
}
}
- 통신 중(model == null)일 때는 CircularProgressIndicator 위젯을 그립니다.
- 통신이 완료되면 Column 위젯을 그립니다.
Share article