📌 이번 글에서는 PostListPage를 구성하고, AutoDisposeNotifier를 사용하여 게시글 목록을 효율적으로 관리하는 방법을 다룹니다.
게시글을 불러오고, 리스트를 렌더링하며, 사용자 경험을 개선하기 위해 PostListItem을 활용합니다.
또한, 뷰모델을 AutoDisposeNotifier로 구현하여 불필요한 상태 유지 및 메모리 누수를 방지하는 방법을 살펴봅니다.
1️⃣ 게시글 모델링 (User, Post, PostList)
📌 User 모델
게시글의 작성자를 나타내는 모델입니다.
// 게시글 주인이 누구인가? --> User 모델 정의
// 인증 여부는 SessionUser 로 진행할 예정
class User {
int? id;
String? username;
String? imgUrl;
User.fromMap(Map<String, dynamic> map)
: id = map["id"],
username = map["username"],
imgUrl = map["imgUrl"];
}
✔ User 정보를 불러와서 게시글과 연결
📌 Post 모델
게시글 하나에 대한 정보를 담는 모델입니다.
import 'package:intl/intl.dart';
import 'user.dart';
class Post {
int? id;
String? title;
String? content;
DateTime? createdAt;
DateTime? updatedAt;
int? bookmarkCount;
bool? isBookmark;
User? user;
Post.fromMap(Map<String, dynamic> map)
: id = map["id"],
title = map["title"],
content = map["content"],
createdAt = DateFormat("yyyy-MM-dd").parse(map["createdAt"]),
updatedAt = DateFormat("yyyy-MM-dd").parse(map["updatedAt"]),
bookmarkCount = map["bookmarkCount"],
isBookmark = map["isBookmark"],
user = User.fromMap(map["user"]);
}
✔ 게시글 제목, 내용, 작성일, 북마크 수, 유저 정보를 포함
📌 PostList 모델
게시글 목록을 한 페이지 단위로 관리하는 모델입니다.
import 'package:class_f_story/data/model/post.dart';
class PostList {
bool isFirst;
bool isLast;
int pageNumber;
int size;
int totalPage;
List<Post> posts;
PostList({
required this.isFirst,
required this.isLast,
required this.pageNumber,
required this.size,
required this.totalPage,
required this.posts,
});
// 팩토리 생성자를 활용하여 JSON 데이터를 객체로 변환
factory PostList.fromMap(Map<String, dynamic> map) {
return PostList(
isFirst: map['isFirst'] ?? false,
isLast: map['isLast'] ?? false,
pageNumber: map['pageNumber'] ?? 0,
size: map['size'] ?? 10,
totalPage: map['totalPage'] ?? 1,
posts: (map['posts'] as List<dynamic>? ?? [])
.map((e) => Post.fromMap(e))
.toList(),
);
}
// 깊은 복사 (객체 변경 시 활용)
PostList copyWith({
bool? isFirst,
bool? isLast,
int? pageNumber,
int? size,
int? totalPage,
List<Post>? posts,
}) {
return PostList(
isFirst: isFirst ?? this.isFirst,
isLast: isLast ?? this.isLast,
pageNumber: pageNumber ?? this.pageNumber,
size: size ?? this.size,
totalPage: totalPage ?? this.totalPage,
posts: posts ?? List<Post>.from(this.posts), // 리스트 깊은 복사
);
}
}
✔ 페이지네이션을 지원하는 PostList 모델
2️⃣ PostListPage 구현
게시글 목록을 표시하는 페이지입니다.
import 'package:class_f_story/ui/pages/post/list_page/widgets/post_list_body_temp.dart';
import 'package:class_f_story/ui/widgets/custom_drawer.dart';
import 'package:flutter/material.dart';
class PostListPage extends StatelessWidget {
final scaffoldKey = GlobalKey<ScaffoldState>();
PostListPage({super.key});
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
key: scaffoldKey,
drawer: CustomDrawer(scaffoldKey),
appBar: AppBar(
title: Text('f-story'),
),
body: PostListBodyTemp(),
),
);
}
}
✔ Drawer를 포함한 기본적인 PostListPage 레이아웃 구성
3️⃣ PostListItem 구현
각 게시글 항목을 표시하는 위젯입니다.
import 'package:flutter/material.dart';
import '../../../../../_core/utils/m_http.dart';
import '../../../../../data/model/post.dart';
class PostListItem extends StatelessWidget {
Post post;
PostListItem(this.post);
@override
Widget build(BuildContext context) {
return ListTile(
title: Text("${post.title}", style: TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text(
"${post.content}",
style: TextStyle(color: Colors.black45),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
trailing: ClipRRect(
borderRadius: BorderRadius.circular(50),
child: Image.asset('assets${post.user!.imgUrl}'),
),
);
}
}
✔ 게시글 제목, 내용, 유저 프로필 이미지 표시
4️⃣ PostListViewModel (AutoDisposeNotifier 적용)
뷰모델을 AutoDisposeNotifier로 구현하여 불필요한 상태 유지 및 메모리 누수 방지
import 'package:class_f_story/_core/utils/exception_handler.dart';
import 'package:class_f_story/data/model/post_list.dart';
import 'package:class_f_story/data/repository/post_repository.dart';
import 'package:class_f_story/main.dart';
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import '../../_core/utils/logger.dart';
class PostListViewModel extends AutoDisposeNotifier<PostList?> {
final refreshController = RefreshController();
final postRepository = const PostRepository();
final mContext = navigatorkey.currentContext!;
@override
PostList? build() {
logger.d('PostListViewModel 초기화 완료');
// AutoDisposeNotifier가 메모리에서 내려갈 때 콜백 실행
ref.onDispose(() {
refreshController.dispose();
});
init();
return null;
}
Future<void> init() async {
try {
Map<String, dynamic> resBody = await postRepository.findAll();
if (!resBody['success']) {
ExceptionHandler.handleException(
resBody['errorMessage'], StackTrace.current);
return;
}
state = PostList.fromMap(resBody);
refreshController.loadComplete();
} catch (e, stackTrace) {
ExceptionHandler.handleException('게시글 불러오기 오류', stackTrace);
}
}
}
✔ AutoDisposeNotifier 적용하여 메모리 관리 최적화
✔ 게시글 목록 API 요청 및 상태 관리
✅ 마무리: 구현된 기능 정리
✔ Post, PostList, User 모델을 정의하여 게시글 데이터 관리
✔ PostListPage 및 PostListItem을 생성하여 게시글 목록 UI 구성
✔ AutoDisposeNotifier를 적용한 PostListViewModel을 활용하여 메모리 누수 방지 및 상태 관리 최적화
✔ refreshController를 사용하여 새로고침 및 추가 데이터 로드 기능 구현
🚀 이번 글에서는 게시글 목록을 효과적으로 관리하기 위해 PostListPage와 AutoDisposeNotifier 적용 방법을 살펴보았습니다.
이제 게시글 목록을 더 효율적으로 관리하고, 최적화된 상태 유지 및 메모리 관리까지 가능해졌습니다! 🎯
'Flutter > App' 카테고리의 다른 글
[Flutter] 블로그 만들기 - pull_to_refresh 라이브러리 사용 (0) | 2025.02.11 |
---|---|
[Flutter] 블로그 만들기 - 게시글 작성 기능 구현 (0) | 2025.02.10 |
[Flutter] 블로그 만들기 - 게시글 관리 및 로그아웃 기능 구현 (0) | 2025.02.10 |
[Flutter] 블로그 만들기 -자동 로그인 기능 구현 및 UI (0) | 2025.02.10 |
[Flutter] 블로그 만들기 - 회원가입 기능 구현 및 UI (1) | 2025.02.09 |