플러터/화면구현
[플러터] RiverPod 상태 관리를 활용한 To-Do List 앱 만들기
JungMayo
2025. 1. 23. 18:24
1. TodoItem 클래스 (todo_item.dart)
TodoItem 클래스는 할 일 데이터를 정의한다. 각 할 일은 제목(title)과 완료 여부(isDone)를 속성으로 가진다.
// To-Do 데이터를 관리하는 모델 클래스이다.
class TodoItem {
String title; // 할 일의 제목이다.
bool isDone; // 완료 여부를 나타낸다.
// 생성자를 통해 데이터를 초기화한다.
TodoItem({required this.title, this.isDone = false});
// 새로운 객체를 생성하면서 일부 데이터를 변경할 수 있는 메서드다.
TodoItem copyWith({String? title, bool? isDone}) {
return TodoItem(
title: title ?? this.title,
isDone: isDone ?? this.isDone,
);
}
}
- copyWith toggleItem 2단계 코드로써 시작 메서드 실행되면 무조건 TodoItem 객체 리턴함
- 매개변수중에 하나만 변경하고 싶을 수도 있는데 그때 쓰면 유용하다.
- null 이라면 원래 있던 값을 넣으라는 의미인데... null 이 들어왔다는건 변화할 값이 없다는 의미로 쓰는 것
2. TodoListViewModel 클래스 (todo_list_view_model.dart)
TodoListViewModel 클래스는 To-Do 데이터를 관리하며 상태 변경 로직을 처리한다.
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_statement_v01/_mvvm/_05/models/todo_item.dart';
// Riverpod Notifier를 사용하여 창고를 생성한다.
class TodoListViewModel extends Notifier<List<TodoItem>> {
@override
List<TodoItem> build() {
return []; // 초기 상태를 빈 리스트로 설정한다.
}
// 할 일을 추가하는 메서드다.
void addItem(String title) {
state = [...state, TodoItem(title: title)];
}
// 할 일의 완료 상태를 토글하는 메서드다.
void toggleItem(TodoItem todo) {
state = state
.map((item) => item == todo ? item.copyWith(isDone: !item.isDone) : item)
.toList();
}
}
// Riverpod Provider로 창고를 등록한다.
final todoListViewModelProvider =
NotifierProvider<TodoListViewModel, List<TodoItem>>(() {
return TodoListViewModel();
});
- state 맵의 item을 돌고 List로 변환하는 형태인데 item과 매개변수인 todo의 값이 같을 때! item의 copyWith를 호출하여 그 안의 매개변수 내용을 변경시킨다. -> 그러면 나머지 내용은 그대로고 해당 isDone 값만 바뀌겠지.
3. TodoListView 위젯 (todo_list_view.dart)
TodoListView는 사용자가 할 일을 추가하고 상태를 변경할 수 있는 UI를 제공한다.
주요 기능
- 텍스트 필드를 사용해 할 일을 입력한다.
- "추가" 버튼을 눌러 새로운 할 일을 등록한다.
- 체크박스를 통해 완료 상태를 변경한다.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_statement_v01/_mvvm/_05/models/todo_item.dart';
import 'package:flutter_statement_v01/_mvvm/_05/view_models/todo_list_view_model.dart';
class TodoListView extends ConsumerWidget {
TodoListView({super.key});
// 텍스트 입력을 제어하는 컨트롤러다.
TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context, WidgetRef ref) {
// 상태를 구독하여 데이터를 가져온다.
final todos = ref.watch(todoListViewModelProvider);
// 상태 변경 메서드를 호출하기 위해 Notifier에 접근한다.
final todoNotifier = ref.watch(todoListViewModelProvider.notifier);
return Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
controller: _controller,
decoration: InputDecoration(
hintText: 'Enter todo item...',
suffixIcon: IconButton(
onPressed: () {
// 텍스트 필드의 내용을 기반으로 새로운 할 일을 추가한다.
todoNotifier.addItem(_controller.text);
_controller.clear();
},
icon: Icon(Icons.add),
),
),
),
),
SizedBox(height: 16.0),
Expanded(
child: ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
final TodoItem item = todos[index];
return ListTile(
title: Text(item.title),
trailing: Checkbox(
value: item.isDone,
onChanged: (value) {
// 체크박스 클릭 시 완료 상태를 변경한다.
todoNotifier.toggleItem(item);
},
),
);
},
),
),
],
);
}
}
4. 주요 개념 정리
- Notifier
- 상태를 관리하며 상태 변경 로직을 포함하는 클래스다.
- build 메서드를 통해 초기 상태를 정의한다.
- NotifierProvider
- Notifier를 사용하는 Provider로 상태 관리 기능을 제공한다.
- ref.watch()를 통해 상태를 구독하며, ref.read()로 상태 변경 메서드를 호출할 수 있다.
- 불변 객체 원칙
- 리스트나 객체를 변경할 때는 기존 데이터를 복사하여 새로운 객체로 할당해야 한다.
- 이를 통해 상태 관리의 안정성과 예측 가능성을 보장한다.
앱의 동작
- 앱 실행: 앱이 실행되면 기본 상태는 빈 리스트이다.
- 할 일 추가: 텍스트 필드에 입력 후 "추가" 버튼을 누르면 리스트에 새로운 할 일이 추가된다.
- 완료 상태 변경: 리스트의 체크박스를 클릭하면 완료 여부가 토글된다.