pubspec.yaml
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.6
provider: ^6.1.2

todo.dart
더보기
// Todo 모델 클래스 - 할 일 데이터를 정의
class Todo {
final String id;
final String title;
// Alt + insert
Todo({required this.id, required this.title});
}
todo_view_model.dart
더보기
// ViewModel 클래스 - 상태와 로직을 담당한다.
import 'package:flutter/material.dart';
import 'package:my_mvvm_v01/start04/models/todo.dart';
// ChangeNotifier 상속 한다.
class TodoViewModel extends ChangeNotifier {
// 데이터가 필요하다.
List<Todo> todos = [];
// 할 일을 추가하는 기능
void addTodo(String title) {
final newTodo = Todo(id: DateTime.now().toString(), title: title);
todos.add(newTodo);
// 상태 알림 호출
notifyListeners();
}
// 할 일을 삭제하는 기능
void removeTodo(String id) {
// for문 돌려서 id가 같으면 삭제된다.
todos.removeWhere( (todo) => todo.id == id);
// UI에 상태가 변경되었다고 알림
notifyListeners();
}
}
todo_screen.dart
더보기
import 'package:flutter/material.dart';
import 'package:my_mvvm_v01/start04/view_models/todo_view_model.dart';
import 'package:provider/provider.dart';
// MaterialApp 앱 안에서 외부 라이브러리(프로바이더) 위젯을 감싸 주어야 한다.
void main() => runApp(
MaterialApp(
// (_) => TodoViewModel() -> 매개변수를 사용하지 않을거면 _ 를 선언한다.
home: ChangeNotifierProvider(
create: (_) => TodoViewModel(),
builder: (context, child) {
return TodoScreen();
},
),
),
);
class TodoScreen extends StatelessWidget {
TodoScreen({super.key});
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('MVVM provider Todo List'),
),
body: Column(
children: [
// 입력 필드 만들기
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(labelText: '작업을 입력 하시오'),
),
),
IconButton(
onPressed: () {
// 여기에서 뷰 모델 클래스를 가져오자 --> DI 처리
final todoViewModel = Provider.of<TodoViewModel>(context, listen: false);
if(_controller.text.isNotEmpty) {
todoViewModel.addTodo(_controller.text);
_controller.clear();
}
},
icon: Icon(Icons.add),
)
],
),
),
// 아래에 할일 목록 표시 구성
// 아래에 할일 목록 표시 구성
Expanded(
child: Consumer<TodoViewModel>(
builder: (context, todoViewModel, child) {
return ListView.builder(
itemCount: todoViewModel.todos.length,
itemBuilder: (context, index) {
// 뷰모델에 있는 자료구조 안에 각 인덱스에 맵핑된 객체 Todo인스턴스 하나
final todo = todoViewModel.todos[index];
return ListTile(
title: Text(todo.title),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => todoViewModel.removeTodo(todo.id),
),
);
},
);
},
),
),
],
),
);
}
}
statelessWidget으로 작성해도 괜찮은 이유는 상태 관리를 ViewModel이 담당하기 때문입니다.
Provider와 ChangeNotifier를 통해 ViewModel이 상태 변화를 관리하고 UI에 반영하기 때문에, UI 위젯이 반드시 StatefulWidget일 필요가 없습니다
정리
- StatefulWidget일 필요가 없는 이유: ChangeNotifier를 통해 ViewModel이 상태를 관리하고, UI가 자동으로 알림을 받기 때문에, UI 자체가 상태를 가지지 않아도 됩니다.
- UI 업데이트 범위 제한: 단, Consumer 위젯으로 변경이 필요한 위젯만 감싸, 필요한 부분만 다시 빌드하게 만듭니다. 이 방식은 성능 최적화에도 유리합니다.
'Flutter' 카테고리의 다른 글
| 2024. 11. 14 Flutter UI 프레임워크 Flutter에서의 위젯 생명 주기 (0) | 2024.11.14 |
|---|---|
| 2024. 11. 14 Flutter UI 프레임워크 플러터 기본기 다지기 - 4 (0) | 2024.11.14 |
| 2024.11. 13 MVVM 패턴과 상태 관리 상태 변화가 있을 때 UI에 자동으로 알림 주기 (0) | 2024.11.13 |
| 2024.11. 13 MVVM 패턴과 상태 관리 (0) | 2024.11.13 |
| 2024. 11. 12 Dio 통신 연습 (0) | 2024.11.12 |