PostListPage - onTab() 추가
import 'package:class_mvvm/models/post.dart';
import 'package:class_mvvm/providers/state_noti_provider/post_list_view_model_provider.dart';
import 'package:class_mvvm/view/post/post_detail_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
// MVVM -> View 는 뷰 모델 인스턴스만 바라보면 된다.
// ConsumerWidget은 Provider 생태를 구독하여, 상태가 변경될 때 자동으로 UI 업데이트 되도록 설계 가능하다.
class PostListPage extends ConsumerWidget {
const PostListPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// 게시글에 리스트 화면을 구현해야 한다
// 뷰 모델을 관리하는 프로바이더를 호출하는데 계속 관찰하는 입장이다.
final postList = ref.watch(postListViewModelProvider);
// List<Post> postList <---
return Scaffold(
appBar: AppBar(
title: Text('게시글 목록 화면'),
),
body: postList.isEmpty
? Center(
child: Text('게시글이 존재 하지 않습니다'),
)
: ListView.separated(itemBuilder: (context, index) {
Post post = postList[index];
return ListTile(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return PostDetailPage(postId: post.id);
}));
},
title: Text(
post.title,
style: TextStyle(color: Colors.orangeAccent),
),
subtitle: Text(post.body),
trailing: IconButton(
onPressed: () async {
bool confirm = await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('삭제'),
content: Text('${post.title} 를 삭제 하시겠습니까?'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text('취소')),
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text('확인'))
],
),
);
// 뷰모델에 접근해서 deletePost() 메서드를 호출해야 한다.
// 상태를 그냥 보는 것은 직접 접근이 가능하다.
// 해당하는 프로바이더에 상태 변경 요청은 창고 관리자한테 의뢰해야 한다.
if (confirm) {
await ref
.read(postListViewModelProvider.notifier)
.deletePost(post.id!);
// 삭제 완료 후 스택바로 피드백 제공
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('삭제 완료')));
}
},
icon: Icon(
Icons.delete,
color: Colors.redAccent,
),
),
);
},
separatorBuilder: (context, index) => const Divider(
thickness: 1,
),
itemCount: postList.length),
);
}
}
lib/view/post/post_detail_page.dart 파일 생성
PostDetailPage 기본 화면 설정
import 'package:flutter/material.dart';
class PostDetailPage extends StatelessWidget {
final postId;
const PostDetailPage({required this.postId, super.key});
@override
Widget build(BuildContext context) {
print('여기는 상세보기 화면 입니다.');
return const Placeholder();
}
}
lib/view_models/post_detail_view_model.dart 파일 생성
PostDetailViewModel 생성
// 뷰 모델 --> 무조건 StateNotifier 상속 받자
// StateNotifier --> 관리해야 하는 상태값은 뭘까?
// StateNotifier <-- 상태는 캡슐화 된다. T _state;
import 'package:class_mvvm/models/post.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../repository/post_repository.dart';
// 외부에서 접근하는 상태 변수는 state 된다 ---> T 제네릭이기 때문에 실제 값은 Post 객체 이다.
class PostDetailViewModel extends StateNotifier<AsyncValue<Post>> {
final PostRepository _postRepository;
final int postId;
// AsyncValue 비동기 통신 (통신을 할때 ) 3가지 상태를 구분 짓어서 화면을 구성하는데 매우 편리하다.
// 1 - 로딩, 2 - 데이터, 3 오류
PostDetailViewModel(this._postRepository, this.postId)
: super(AsyncValue.loading()) {
// 객체 생성시에 비즈니스 로직 호출
fetchPostGetById();
}
// 특정 게시글 요청 기능
Future<void> fetchPostGetById() async {
try {
// 응답 받은 post 객체
final post = await _postRepository.fetchPostById(postId);
state = AsyncValue.data(post);
} catch (e, stackTrace) {
// e : 오류 메세지
// stackTrace : 개발 시점에 어디서 오류가 발생 했는지 추적 계층 구조를 던져 준다.
state = AsyncValue.error(2, stackTrace);
throw Exception('통신중 오류 발생 $e');
}
}
}
AsyncValue를 사용하면 비동기 상태를 효율적으로 관리할 수 있는 여러 장점이 있습니다. AsyncValue는 비동기 작업의 세 가지 주요 상태(로딩, 성공, 오류)를 쉽게 표현할 수 있는 타입으로, 비동기 작업과 관련된 UI를 구현할 때 유용합니다. 즉, 데이터의 상태와 화면에 보여줄 UI를 좀 더 쉽게 처리할 수 있습니다. 비동기 상태(로딩 중, 성공, 오류)에 따라 적절한 UI를 작성하기 쉽습니다.
postState.when(
loading: () => CircularProgressIndicator(),
data: (post) => Text(post.title),
error: (e, stack) => Text('오류 발생: $e'),
);
'Flutter > MVVM 활용' 카테고리의 다른 글
[Flutter] (MVVM 활용) PostDetailView 화면 완성 하기 - 11 (0) | 2024.11.22 |
---|---|
[Flutter] (MVVM 활용) PostDetailViewModel을 Provider 통해서 관리 해보자. - 10 (0) | 2024.11.22 |
[Flutter] (MVVM 활용) PostListPage 화면을 만들어 보자 그런데 뷰 모델은 어떻게 가지고 올까? - 8 (0) | 2024.11.19 |
[Flutter] (MVMM 활용) viewModel 을 관리하는 Provider 계열을 만들어 보자 - 7 (0) | 2024.11.19 |
[Flutter] (MVVM 활용) 화면의 데이터(상태)를 관리하는 PostListViewModel 을 먼저 만들어 보자. - 6 (0) | 2024.11.19 |