GREEN나무 2025. 5. 15. 09:47
728x90

Provider를 활용한 Flutter 상태 관리 가이드


학습 목표

  • Provider 패키지의 역할과 구조 이해
  • ChangeNotifier 기반 상태 관리 흐름 파악
  • Provider.of, Consumer, Selector 사용법 숙지
  • MultiProvider를 활용한 복합 상태 관리 구성
  • 간단한 ToDo 앱을 통해 상태 추가·삭제·업데이트 실습

1. 사전 준비

  1. Flutter SDK 설치 및 기본 프로젝트 생성
  2. pubspec.yaml에 Provider 패키지 추가 
    dependencies:
      flutter:
        sdk: flutter
      provider: ^6.0.5
  3. 터미널에서 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) 앱

  1. 모델 정의
    • 위 2.1의 TodoList 클래스 사용
  2. Provider 등록
    void main() {
      runApp(
        ChangeNotifierProvider(
          create: (_) => TodoList(),
          child: const MyApp(),
        ),
      );
    }

  3. 할 일 추가 화면
    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('추가'),
            ),
          ],
        );
      }
    }

  4. 할 일 목록 화면
    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. 실습

  1. 일기 작성 화면
    • DiaryDraft ChangeNotifier 만들어 입력 상태 관리
  2. 복합 위젯 상태 동기화
    • MultiProvider로 여러 ChangeNotifier 한 번에 등록
  3. 실시간 데이터 연동
    • 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