import 'package:flutter_riverpod/flutter_riverpod.dart';
// 1. 기본 창고를 설계 해 보자(변경 안되는 값들)
// 창고 메뉴얼 필요 없다
// 타입 안정성 설계 --> 제네릭 명시
final productsProvider = Provider<List<String>>((ref) {
return ['사과', '바나나', '우유', '빵'];
});
// 2. 복합 창고를 만들기 전에 - 상테를 먼저 결정해야 한다(값 - 객체)
/// 사과나 바나나 등을 담을 수 있는 객체를 설계 해야 한다.
/// 2-1 상태를 먼저 설계 한다 (보통은 클래스 설계)
/// 상태 --> 객체 (불변 객체)
/// --> 접근 해서 상태 값을 변경 하면 오류가 발생할 수 있기 때문
class Cart {
List<String> items;
Cart({required this.items});
}
/// 2-2 창고 매뉴얼 설계도
class CartNotifier extends Notifier<Cart> {
/// 중요 변수 - Notifier 클래스를 상속 받으면 state 변수가 기본적으로 있다. ///
// 반드시 초기 상태가 어떤지 명시해 주어야 한다.
/// 필수 ///
@override
Cart build() {
return Cart(items: []);
}
// 상품을 추가하는 방법
void add(String item) {
// 불변 객체로 설계
// 기존 리스트 + 새 상품 = 새로운 자료 구조 생성
final newItems = [...state.items, item];
state = Cart(items: newItems);
}
// 상품을 제거하는 방법
void remove(String item) {
// list 특정 조건을 확인하고 새로운 리스트를 만들어주는 메서드
// ['사과', '바나나']
// '바나나'
final List<String> newItems =
state.items.where((element) => element != item).toList();
state = Cart(items: newItems);
}
}
/// 2-3 실제 창고 생성 / 메뉴얼과 창고 데이터 명시
final cartProvider = NotifierProvider<CartNotifier, Cart>(() => CartNotifier());
shopping_app.dart
import 'package:flutter/material.dart';
import 'package:flutter_blog/_test_code/providers.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
// 창고 시스템을 도입 - StatelessWidget 확장 --> ConsumerWidget 변겅
class ShoppingApp extends ConsumerWidget {
const ShoppingApp({super.key});
// WidgetRef ref - 통로
@override
Widget build(BuildContext context, WidgetRef ref) {
// 내가 만든 창고(productsProvider)에 접근해 --> 창고에서 관리하는 데이터 반환
// ['사과', '바나나', '우유', '빵']
final List<String> products = ref.read(productsProvider);
final Cart cart = ref.watch(cartProvider);
// ref.watch(provider) <-- 계속 구독
// ref.read(provider) <-- 단 한번 요청
return Scaffold(
appBar: AppBar(
title: Text('상점'),
actions: [
// 장바구니 개수 표시
Center(child: Text('장바구니 ${cart.items.length} 개')),
const SizedBox(width: 20),
],
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
final String product = products[index];
return ListTile(
title: Text(product),
trailing: ElevatedButton(
onPressed: () {
// 상태 공유
// 창고에 데이터 추가 (기능)
// ref.read(cartProvider) --> 창고 데이터를 반환
// ref.read(cartProvider.notifier) --> 창고 메뉴얼에 접근
ref.read(cartProvider.notifier).add(product);
},
child: Text('담기')),
);
},
),
),
Expanded(
child: Column(
children: [
Text(
'장바구니',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
Expanded(
child: ListView.builder(
itemCount: cart.items.length,
itemBuilder: (context, index) {
final String item = cart.items[index];
return ListTile(
title: Text(item),
trailing: IconButton(
onPressed: () {
ref.read(cartProvider.notifier).remove(item);
},
icon: Icon(Icons.remove),
),
);
},
),
),
],
),
)
],
),
);
}
}