9강: 실제 프로젝트에서 Provider 사용하기 – 상태 관리 실전 예제

9강: 실제 프로젝트에서 Provider 사용하기 – 상태 관리 실전 예제


지금까지 우리는 Provider를 통해 Flutter의 상태 관리를 이해해 왔어. 이번 강의에서는 실제 프로젝트에서 Provider를 어떻게 사용할 수 있는지에 대해 실전 예제를 통해 알아볼 거야. 지금까지 배운 내용을 바탕으로, 실제 앱에서 상태 관리가 어떻게 적용되는지 이해하면 더욱 유용할 거야.


실전 예제: 간단한 쇼핑 목록 앱 만들기

이번 예제에서는 간단한 쇼핑 목록 앱을 만들어 볼 거야. 사용자는 상품을 추가하고 삭제할 수 있으며, 전체 상품 목록을 볼 수 있어. 이 앱을 통해 상태 관리가 실제로 어떻게 이루어지는지 확인해 보자.

1) 프로젝트 준비 및 구조 설정

우선, 새로운 Flutter 프로젝트를 생성하고 필요한 디렉토리를 구성해 보자:

  • lib/models/item.dart: 쇼핑 아이템 모델 클래스.
  • lib/providers/item_provider.dart: 아이템 목록을 관리하는 Provider.
  • lib/screens/home_screen.dart: 메인 화면 UI.

pubspec.yamlprovider 패키지를 추가해:

dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.0

이후 flutter pub get을 통해 패키지를 설치하자.

2) 모델 클래스 작성하기

먼저 쇼핑 아이템을 나타낼 간단한 모델 클래스를 작성해 보자:

class Item {
  final String name;
  final int quantity;

  Item({required this.name, required this.quantity});
}

이 클래스는 이름과 수량을 가진 아이템을 나타내는 단순한 데이터 모델이야.

3) Provider 클래스 작성하기

이제 상태를 관리할 ItemProvider를 작성해 보자. 이 Provider는 아이템 목록을 관리하고 새로운 아이템을 추가하거나 삭제하는 기능을 제공할 거야.

import 'package:flutter/foundation.dart';
import '../models/item.dart';

class ItemProvider with ChangeNotifier {
  List<Item> _items = [];

  List<Item> get items => _items;

  void addItem(String name, int quantity) {
    _items.add(Item(name: name, quantity: quantity));
    notifyListeners();
  }

  void removeItem(int index) {
    _items.removeAt(index);
    notifyListeners();
  }
}

여기서 ChangeNotifier를 상속받아서 상태를 변경할 때마다 notifyListeners()를 호출해 UI가 업데이트되도록 하고 있어.

4) MultiProvider로 상태 연결하기

이제 main.dart 파일에서 MultiProvider를 설정해 ItemProvider를 앱 전체에 제공해 보자.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'providers/item_provider.dart';
import 'screens/home_screen.dart';

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => ItemProvider()),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

이제 ItemProvider를 앱에서 사용할 준비가 완료됐어.

5) 홈 화면 UI 작성하기

이제 홈 화면 UI를 작성해보자. 사용자는 아이템을 추가하고, 목록에서 삭제할 수 있어.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/item_provider.dart';

class HomeScreen extends StatelessWidget {
  final TextEditingController _nameController = TextEditingController();
  final TextEditingController _quantityController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Shopping List'),
      ),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              children: [
                TextField(
                  controller: _nameController,
                  decoration: InputDecoration(labelText: 'Item Name'),
                ),
                TextField(
                  controller: _quantityController,
                  decoration: InputDecoration(labelText: 'Quantity'),
                  keyboardType: TextInputType.number,
                ),
                ElevatedButton(
                  onPressed: () {
                    final name = _nameController.text;
                    final quantity = int.tryParse(_quantityController.text) ?? 1;
                    if (name.isNotEmpty) {
                      Provider.of<ItemProvider>(context, listen: false)
                          .addItem(name, quantity);
                      _nameController.clear();
                      _quantityController.clear();
                    }
                  },
                  child: Text('Add Item'),
                ),
              ],
            ),
          ),
          Expanded(
            child: Consumer<ItemProvider>(
              builder: (context, itemProvider, child) {
                return ListView.builder(
                  itemCount: itemProvider.items.length,
                  itemBuilder: (context, index) {
                    final item = itemProvider.items[index];
                    return ListTile(
                      title: Text('${item.name} (x${item.quantity})'),
                      trailing: IconButton(
                        icon: Icon(Icons.delete),
                        onPressed: () {
                          Provider.of<ItemProvider>(context, listen: false)
                              .removeItem(index);
                        },
                      ),
                    );
                  },
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}
  • TextField와 버튼을 사용하여 사용자가 쇼핑 아이템을 추가할 수 있도록 하고, Consumer를 사용해 ItemProvider의 상태를 UI에 반영하고 있어.
  • 리스트에 있는 아이템은 ListTile로 표현되며, 삭제 버튼을 통해 쉽게 삭제할 수 있어.

실제 프로젝트에서의 상태 관리

이 예제는 간단하지만, 실제 프로젝트에서 상태를 관리하는 데 있어 중요한 개념들을 모두 담고 있어. Provider를 통해 상태를 중앙에서 관리하고, UI와 상태의 연결을 쉽게 만들어 주지. 특히 여러 상태가 동시에 관리되는 복잡한 상황에서도 MultiProvider를 통해 깔끔하게 해결할 수 있어.

이런 상태 관리 기법은 규모가 큰 프로젝트에서도 활용되며, 상태가 복잡해질수록 Provider의 효용성은 더 빛나게 돼. 또한 팀 단위로 개발할 때는 코드의 가독성과 관리의 용이성을 높여줘.


마무리

이번 강의에서는 실제 프로젝트에서 Provider를 사용하여 상태를 관리하는 방법을 알아봤어. 간단한 쇼핑 목록 앱을 예제로 들어 상태 관리가 어떻게 이루어지는지, 그리고 ConsumerMultiProvider를 어떻게 활용하는지 살펴보았지. 다음 강의에서는 다른 상태 관리 도구와의 비교를 통해 어떤 상황에서 어떤 도구를 사용하는 것이 적절한지 탐구해 볼 거야. 계속해서 Flutter의 상태 관리에 대해 깊이 탐구해 나가자!