FutureBuilder와 StreamBuilder는 Flutter에서 비동기 데이터를 UI로 렌더링하기 위해 사용됩니다. 주로 데이터의 업데이트 빈도와 지속성에 따라 선택됩니다.
아래는 setState와 함께 사용하는 FutureBuilder를 기반으로 작성한 예제입니다:
FutureBuilder<List<ScheduleTableData>>(
future: GetIt.I<AppDatabase>().getSchedules(selectedDay), // 한 번 데이터를 가져옴
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(), // 로딩 중 표시
);
}
if (snapshot.hasError) {
return Center(
child: Text('오류 발생: ${snapshot.error}'),
);
}
final schedules = snapshot.data ?? []; // 데이터 로드 완료
return ListView.builder(
itemCount: schedules.length,
itemBuilder: (context, index) {
final schedule = schedules[index];
return Dismissible(
key: ObjectKey(schedule.id),
direction: DismissDirection.endToStart,
onDismissed: (DismissDirection direction) {
GetIt.I<AppDatabase>().removeSchedule(schedule.id);
setState(() {}); // FutureBuilder를 다시 실행하여 UI 갱신
},
child: ScheduleCard(
startTime: schedule.startTime,
endTime: schedule.endTime,
content: schedule.content,
color: Color(int.parse('FF${schedule.color}', radix: 16)),
),
);
},
);
},
);
아래는 confirmDismiss와 함께 사용하는 StreamBuilder를 기반으로 작성한 예제입니다:
StreamBuilder<List<ScheduleTableData>>(
stream: GetIt.I<AppDatabase>().streamSchedules(selectedDay), // 지속적으로 데이터를 감시
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(), // 로딩 중 표시
);
}
if (snapshot.hasError) {
return Center(
child: Text('오류 발생: ${snapshot.error}'),
);
}
final schedules = snapshot.data ?? []; // 실시간 데이터 반영
return ListView.builder(
itemCount: schedules.length,
itemBuilder: (context, index) {
final schedule = schedules[index];
return Dismissible(
key: ObjectKey(schedule.id),
direction: DismissDirection.endToStart,
confirmDismiss: (DismissDirection direction) async {
final confirm = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text('삭제 확인'),
content: Text('정말로 삭제하시겠습니까?'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text('취소'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text('삭제'),
),
],
),
);
if (confirm == true) {
await GetIt.I<AppDatabase>().removeSchedule(schedule.id);
return true; // 삭제 확정
}
return false; // 삭제 취소
},
child: ScheduleCard(
startTime: schedule.startTime,
endTime: schedule.endTime,
content: schedule.content,
color: Color(int.parse('FF${schedule.color}', radix: 16)),
),
);
},
);
},
);
setState를 호출해 FutureBuilder를 다시 실행합니다.setState 호출은 드물게 사용됩니다.setState의 필요성이 줄어듭니다.예제를 통해 상황에 맞는 도구를 적절히 사용하세요! 🚀