Flutter + Dart/Flutter + Dart 공부
Provider
GREEN나무
2025. 5. 15. 09:47
728x90
Provider를 활용한 Flutter 상태 관리 가이드
학습 목표
- Provider 패키지의 역할과 구조 이해
- ChangeNotifier 기반 상태 관리 흐름 파악
- Provider.of, Consumer, Selector 사용법 숙지
- MultiProvider를 활용한 복합 상태 관리 구성
- 간단한 ToDo 앱을 통해 상태 추가·삭제·업데이트 실습
1. 사전 준비
- Flutter SDK 설치 및 기본 프로젝트 생성
- pubspec.yaml에 Provider 패키지 추가
dependencies: flutter: sdk: flutter provider: ^6.0.5
- 터미널에서 flutter pub get 실행
2. 핵심 개념 정리
2.1 ChangeNotifier
- 상태 변경 시 notifyListeners() 호출
- 리스너(위젯)에 변경 알림 전달
class TodoList extends ChangeNotifier {
final List<String> _items = [];
List<String> get items => List.unmodifiable(_items);
void add(String task) {
_items.add(task);
notifyListeners();
}
void removeAt(int index) {
_items.removeAt(index);
notifyListeners();
}
}
2.2 Provider.of
- 위젯 트리 상단에 등록된 Provider에서 상태 읽기
- 읽기 전용: listen: false 지정 가능
final todoList = Provider.of<TodoList>(context, listen: false);
2.3 Consumer
- 특정 상태가 변경될 때만 재빌드
- builder 내부에서 상태 접근
Consumer<TodoList>(
builder: (context, todoList, child) {
return ListView.builder(
itemCount: todoList.items.length,
itemBuilder: (_, idx) => Text(todoList.items[idx]),
);
},
),
2.4 Selector
- 상태의 일부분만 선택해 효율적으로 빌드
- selector에서 반환한 값이 바뀔 때만 재빌드
Selector<TodoList, int>(
selector: (_, todo) => todo.items.length,
builder: (_, count, __) => Text('총 할 일: $count'),
),
2.5 MultiProvider
- 여러 Provider를 한 곳에서 묶어 등록
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => TodoList()),
ChangeNotifierProvider(create: (_) => DiaryDraft()),
],
child: MyApp(),
),
3. 실습 예제: 할 일 목록(ToDo) 앱
- 모델 정의
- 위 2.1의 TodoList 클래스 사용
- Provider 등록
void main() { runApp( ChangeNotifierProvider( create: (_) => TodoList(), child: const MyApp(), ), ); }
- 할 일 추가 화면
class AddTodoPage extends StatelessWidget { final TextEditingController _controller = TextEditingController(); @override Widget build(BuildContext context) { return Column( children: [ TextField(controller: _controller), ElevatedButton( onPressed: () { final text = _controller.text; if (text.isNotEmpty) { Provider.of<TodoList>(context, listen: false).add(text); Navigator.pop(context); } }, child: const Text('추가'), ), ], ); } }
- 할 일 목록 화면
class TodoPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('할 일 목록')), body: Consumer<TodoList>( builder: (_, todo, __) => ListView.builder( itemCount: todo.items.length, itemBuilder: (_, idx) => ListTile( title: Text(todo.items[idx]), trailing: IconButton( icon: const Icon(Icons.delete), onPressed: () => todo.removeAt(idx), ), ), ), ), floatingActionButton: FloatingActionButton( child: const Icon(Icons.add), onPressed: () => Navigator.push( context, MaterialPageRoute(builder: (_) => AddTodoPage()), ), ), ); } }
4. 추가 옵션 및 팁
- context.watch<T>() / context.read<T>() / context.select<T, R>()
- watch : 빌드 중 상태 변경 감지 → 위젯 전체 재빌드
- read : 읽기 전용, 리스너 등록 안 함 → 상태 읽기만 할 때
- select : 상태 일부만 골라서 감지 → 변경된 부분만 재빌드
- Provider.value 주의사항
- 기존 ChangeNotifier를 전달할 때 사용
- 위젯이 dispose 될 때 자동으로 해제되지 않으니, 직접 dispose() 관리 필요
- BLoC/Cubit vs Provider
- Provider : 간단·가볍게 상태 공유
- BLoC/Cubit : 이벤트 기반, 테스트·유지보수에 강점
5. 실습
- 일기 작성 화면
- DiaryDraft ChangeNotifier 만들어 입력 상태 관리
- 복합 위젯 상태 동기화
- MultiProvider로 여러 ChangeNotifier 한 번에 등록
- 실시간 데이터 연동
- API 호출은 FutureProvider
- 스트림 처리 시 StreamProvider
참고 링크
https://pub.dev/packages/provider
https://docs.flutter.dev/data-and-backend/state-mgmt/simple
https://pub.dev/documentation/provider/latest/provider/Consumer-class.html
https://pub.dev/documentation/provider/latest/provider/Selector-class.html
https://pub.dev/documentation/provider/latest/provider/Provider/of.html
https://docs.flutter.dev/data-and-backend/state-mgmt/options