Flutter

[Flutter] 41. ChangeNotifier란?

Song hyun 2024. 11. 13. 11:01
728x90
반응형

[Flutter] 41. ChangeNotifier란?

 

*ChangeNotifier는 Flutter에서 상태 변화가 있을 때, UI에 자동으로 알림을 주기 위한 클래스이다.

*MVVM 패턴에서 ViewModel을 통해 UI와 데이터를 연결하는 데 매우 유용하다.

 

 

시나리오 코드

(1) View-model에서 ChangeNotifier 상속 처리

// ChangeNotifier를 상속한다.
class TodoViewModel extends ChangeNotifier
  // 할 일을 추가하는 기능
void addTodo(String title){
  final newTodo = Todo(id: DateTime.now().toString(), title: title);
  todos.add(newTodo);
  // 상태 알림 호출
  notifyListeners();
}

// 할 일을 삭제하는 기능
void removeTodo(String id){
  todos.removeWhere((todo)=>todo.id == id);
  // UI에 상태가 변경되었다고 알림
  notifyListeners();

 

 

(2) ChangeNotifier를 사용한 View 클래스 리팩토링

import 'package:flutter/material.dart';
import 'package:my_mvvm_v01/start03/view_models/todo_view_model.dart';

void main() => runApp(MaterialApp(home: TodoScreen()));

class TodoScreen extends StatefulWidget {
  const TodoScreen({super.key});

  @override
  State<TodoScreen> createState() => _TodoScreenState();
}

class _TodoScreenState extends State<TodoScreen> {
  // MVVM 패턴이기 때문에 View 는 ViewModel 클래스만 참조 하면 된다.
  final TodoViewModel todoViewModel = TodoViewModel();
  final TextEditingController _controller = new TextEditingController();


  @override
  void initState() {
    super.initState();
    // 단 한번만 호출 되는 메서드
    todoViewModel.addListener(() {
      // UI 재 렌더링 메서드
      setState(() {});
    });
  }

  @override
  void dispose() {
    todoViewModel.dispose();
    _controller.dispose();
    super.dispose();
  }

  // 프레젠테이션 로직을 함수화 시키자
  void _addTodo() {
    if(_controller.text.isNotEmpty) {
      todoViewModel.addTodo(_controller.text);
      _controller.clear();
    }
  }

  // 프레젠테이션 로직
  void _removeTodo(String id) {
    todoViewModel.removeTodo(id);
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('MVVM Basic 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: _addTodo,
                  icon: Icon(Icons.add),
                )
              ],
            ),
          ),
          // 아래에 할일 목록 표시 구성
          Expanded(
            child: 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: () => _removeTodo(todo.id),
                    ),
                  );
                }),
          ),
        ],
      ),
    );
  }
}
728x90
반응형