일시적 상태(ephemeral state)와 앱 상태(app state)의 차이점을 설명해주세요.

질문

Flutter에서 일시적 상태(ephemeral state)와 앱 상태(app state)의 차이점을 설명해주세요.

답변

Flutter에서 상태는 크게 일시적 상태(ephemeral state)와 앱 상태(app state)로 나눌 수 있습니다. 이 두 유형의 상태는 관리 방식과 사용 목적에서 중요한 차이가 있습니다.

일시적 상태(Ephemeral State)

일시적 상태는 다음과 같은 특징이 있습니다:

  1. 범위: 단일 위젯이나 작은 위젯 그룹 내에서만 관련이 있는 로컬 상태입니다.

  2. 생명주기: 위젯이 화면에 존재하는 동안만 필요한 임시적인 상태입니다.

  3. 관리 방법: 주로 StatefulWidgetsetState() 메서드를 사용하여 관리합니다.

  4. 예시:

    • 페이지 스크롤 위치
    • 애니메이션 진행 상태
    • 폼 필드의 현재 값
    • 체크박스, 라디오 버튼의 선택 상태
    • 탭 컨트롤러의 현재 탭 인덱스
  5. 복잡성: 비교적 단순하고 관리가 쉽습니다.

일시적 상태 예시 코드

class ExpandableCard extends StatefulWidget {
  @override
  _ExpandableCardState createState() => _ExpandableCardState();
}

class _ExpandableCardState extends State<ExpandableCard> {
  // 일시적 상태: 카드가 확장되었는지 여부
  bool _isExpanded = false;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        // 상태 업데이트
        setState(() {
          _isExpanded = !_isExpanded;
        });
      },
      child: AnimatedContainer(
        duration: Duration(milliseconds: 300),
        height: _isExpanded ? 200 : 100,
        color: Colors.blue,
        child: Center(
          child: Text(
            _isExpanded ? '접기' : '펼치기',
            style: TextStyle(color: Colors.white),
          ),
        ),
      ),
    );
  }
}

앱 상태(App State)

앱 상태는 다음과 같은 특징이 있습니다:

  1. 범위: 앱의 여러 부분에서 공유되는 데이터로, 앱 전체 또는 여러 위젯에 영향을 미칩니다.

  2. 생명주기: 일반적으로 앱 세션 전체 또는 여러 화면에 걸쳐 유지되어야 하는 상태입니다.

  3. 관리 방법: Provider, Riverpod, BLoC, Redux 등과 같은 상태 관리 솔루션을 사용합니다.

  4. 예시:

    • 사용자 로그인 정보
    • 장바구니 내용
    • 앱 설정 및 환경 설정
    • 네트워크에서 가져온 데이터
    • 여러 화면에서 필요한 상품 목록
  5. 복잡성: 일반적으로 더 복잡하며, 구조화된 관리 방법이 필요합니다.

앱 상태 예시 코드 (Provider 사용)

// 상태 모델
class CartModel extends ChangeNotifier {
  final List<Product> _items = [];

  List<Product> get items => _items;
  int get totalItems => _items.length;

  void addProduct(Product product) {
    _items.add(product);
    notifyListeners();
  }

  void removeProduct(Product product) {
    _items.remove(product);
    notifyListeners();
  }
}

// 메인 앱
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => CartModel(),
      child: MyApp(),
    ),
  );
}

// 제품 목록 화면
class ProductListScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('제품 목록'),
        actions: [
          // 장바구니 아이콘과 아이템 개수 표시
          Consumer<CartModel>(
            builder: (context, cart, child) {
              return Badge(
                label: Text('${cart.totalItems}'),
                child: IconButton(
                  icon: Icon(Icons.shopping_cart),
                  onPressed: () {
                    Navigator.pushNamed(context, '/cart');
                  },
                ),
              );
            },
          ),
        ],
      ),
      body: ListView.builder(
        itemBuilder: (context, index) {
          return ProductTile(product: availableProducts[index]);
        },
        itemCount: availableProducts.length,
      ),
    );
  }
}

// 제품 타일 위젯
class ProductTile extends StatelessWidget {
  final Product product;

  ProductTile({required this.product});

  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Text(product.name),
      subtitle: Text('${product.price}원'),
      trailing: IconButton(
        icon: Icon(Icons.add_shopping_cart),
        onPressed: () {
          // 앱 상태 업데이트
          context.read<CartModel>().addProduct(product);
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('${product.name} 장바구니에 추가됨')),
          );
        },
      ),
    );
  }
}

두 상태 유형의 주요 차이점

특성 일시적 상태 (Ephemeral State) 앱 상태 (App State)
범위 단일 위젯 또는 작은 위젯 그룹 앱 전체 또는 여러 위젯
지속성 위젯 생명주기 동안만 유지 앱 세션 또는 영구 저장 가능
관리 방법 setState() Provider, BLoC, Redux 등
복잡성 단순, 적은 코드 복잡, 구조화된 코드 필요
데이터 흐름 지역적, 상향식 전역적, 하향식
디버깅 간단 더 복잡하지만 구조화됨
테스트 위젯 테스트만으로 충분 단위 테스트, 통합 테스트 필요

선택 기준

어떤 유형의 상태를 사용할지 결정할 때 고려할 사항:

  1. 데이터의 범위: 데이터가 단일 위젯이나 화면에만 필요하다면 일시적 상태, 여러 위젯이나 화면에서 필요하다면 앱 상태로 관리합니다.

  2. 데이터의 지속성: 화면이 재구성되거나 다른 화면으로 이동할 때 데이터가 유지되어야 한다면 앱 상태로 관리합니다.

  3. 데이터의 복잡성: 단순한 플래그나 값은 일시적 상태로, 복잡한 객체나 컬렉션은 앱 상태로 관리하는 것이 효율적입니다.

실제 앱에서의 상태 분리 예시

실제 애플리케이션에서는 두 가지 상태 유형을 함께 사용하는 것이 일반적입니다:

class ProductDetailScreen extends StatefulWidget {
  final int productId;

  ProductDetailScreen({required this.productId});

  @override
  _ProductDetailScreenState createState() => _ProductDetailScreenState();
}

class _ProductDetailScreenState extends State<ProductDetailScreen> {
  // 일시적 상태: 현재 선택된 이미지 인덱스
  int _selectedImageIndex = 0;

  @override
  Widget build(BuildContext context) {
    // 앱 상태: 제품 데이터와 장바구니
    final productRepository = context.watch<ProductRepository>();
    final cartModel = context.read<CartModel>();

    // 앱 상태에서 제품 정보 가져오기
    final product = productRepository.getProductById(widget.productId);

    return Scaffold(
      appBar: AppBar(title: Text(product.name)),
      body: Column(
        children: [
          // 이미지 슬라이더 (일시적 상태 사용)
          ImageSlider(
            images: product.images,
            selectedIndex: _selectedImageIndex,
            onIndexChanged: (index) {
              setState(() {
                _selectedImageIndex = index;
              });
            },
          ),

          // 제품 정보 표시 (앱 상태 사용)
          ProductInfo(product: product),

          // 장바구니 추가 버튼 (앱 상태 업데이트)
          ElevatedButton(
            onPressed: () => cartModel.addProduct(product),
            child: Text('장바구니에 추가'),
          ),
        ],
      ),
    );
  }
}

결론

적절한 상태 관리 방식을 선택하는 것은 앱의 구조와 확장성에 큰 영향을 미치므로, 앱의 요구사항을 고려하여 신중하게 결정해야 합니다. 대부분의 실제 애플리케이션은 두 가지 상태 유형을 모두 사용하며, 각 상태의 특성과 요구사항에 맞는 접근 방식을 선택하는 것이 중요합니다.

results matching ""

    No results matching ""