Flutter

[Flutter] Provider 라이브러리를 사용해보기 (코드 발전 시키기 2)

미로910 2024. 11. 13. 13:04
dependencies:
  flutter:
    sdk: flutter
  provider: ^6.1.2

 

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 --> 가능한 한 많은 공간을 차지
                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 --> 오른쪽
                        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 위젯으로 변경이 필요한 위젯만 감싸, 필요한 부분만 다시 빌드하게 만듭니다. 이 방식은 성능 최적화에도 유리합니다.