[Flutter/dart] flutter riverpod provider 에서 provider 쓰기!

houndhollis·2023년 12월 19일
0
post-thumbnail

아직 조금 적응이 안되긴 하는데 한번 작성해보겠다! 우선 우리가 알아야 할 정보
이전 포스팅 에서도 게시했지만 model 부분은 빼고 보기 좋게 초기 설정 코드만 작성 해보겠다.

final shoppingListProvider =
    StateNotifierProvider<ShoppingListNotifier, List<ShoppingItemModel>>(
  (ref) => ShoppingListNotifier(),
);

class ShoppingListNotifier extends StateNotifier<List<ShoppingItemModel>> {
  ShoppingListNotifier()
      : super(
          [
            ShoppingItemModel(
              name: '김치',
              quantity: 3,
              hasBought: false,
              isSpicy: true,
            ),
            ShoppingItemModel(
              name: '라면',
              quantity: 5,
              hasBought: false,
              isSpicy: true,
            ),
            ShoppingItemModel(
              name: '삼겹살',
              quantity: 10,
              hasBought: false,
              isSpicy: false,
            ),
            ShoppingItemModel(
              name: '수박',
              quantity: 2,
              hasBought: false,
              isSpicy: false,
            ),
            ShoppingItemModel(
              name: '카스테라',
              quantity: 5,
              hasBought: false,
              isSpicy: false,
            ),
          ],
        );

void toggleHasBought({required String name}) {
    state = state
        .map((e) => e.name == name
            ? ShoppingItemModel(
                name: e.name,
                quantity: e.quantity,
                hasBought: !e.hasBought,
                isSpicy: e.isSpicy,
              )
            : e)
        .toList();
  }
}

상태가 하나 정의되어 있다.
오늘 해볼 것은 Provider 안에서 Provider! 한번 진행 해보겟다!

FilterListProvider 생성

final filterListProvider = Provider((ref) =>
ref.watch(shoppingListProvider));

간단하게 상태를 하나 만들어준다.

Screen 파일

class ProviderScreen extends ConsumerWidget {
  const ProviderScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final state = ref.watch(filterListProvider);

    return DefaultLayout(
      title: 'ProviderScreen',
      body: ListView(
        children: state
            .map(
              (e) => CheckboxListTile(
                title: Text(e.name),
                value: e.hasBought,
                onChanged: (value) {
                  ref.read(shoppingListProvider.notifier).toggleHasBought(name: e.name);
                },
              ),
            )
            .toList(),
      ),
    );
  }
}

간단하게 코드 설명하면 미리 Component로 만든 DefaultLayout 파일이 있으며, 해당 코드로 작성 했을 경우

이미지 처럼 결과물이 나오는 것을 확인할 수 있다.

이번에는 AppBar 에다가 PopupButton을 만들어 보겠다.

Enum & Provider 추가

enum FilteredState {
  spicy,
  notSpicy,
  all
}

final spicyProvider = StateProvider((ref) => FilteredState.all);

만들어 준 후,

actions: [
        PopupMenuButton(
          itemBuilder: (_) => FilteredState.values
              .map(
                (e) => PopupMenuItem(
                  value: e,
                  child: Text(e.name),
                ),
              )
              .toList(),
        ),
      ],

AppBar actions 에다가 넣어준다.

이미지와 같이 정상 작동되는 것을 알수 있다.

PopupMenuButton(
          itemBuilder: (_) => FilteredState.values
              .map(
                (e) => PopupMenuItem(
                  value: e,
                  child: Text(e.name),
                ),
              )
              .toList(),
          onSelected: (value) {
            print(value);
          },
        ),

onSelected 부분을 추가해서 print 를 확인하면
flutter: FilteredState.notSpicy
flutter: FilteredState.spicy
flutter: FilteredState.all

이런식으로 찍히는 것을 볼수있다. 상태를 변경해보자!

상태변경

onSelected: (value) {
            ref.read(spicyProvider.notifier).update((state) => value);
          },

이제 팝업으로 값을 변경할수 있다.

추가 동작 우리는 이제 spicy 음식과 notSpicy 음식으로 filter를 해볼것이다.

final filterListProvider = Provider((ref) {
  final filterState = ref.watch(spicyProvider);
  final shoppingListState = ref.watch(shoppingListProvider);

  if (filterState == FilteredState.all) {
    return shoppingListState;
  }
  
  return shoppingListState.where((element) => filterState == FilteredState.spicy ? element.isSpicy : !element.isSpicy).toList();
});

enum FilteredState {
  spicy,
  notSpicy,
  all
}

final spicyProvider = StateProvider((ref) => FilteredState.all);

filterState 는 spicyProvider , select 로 변경한 값을 계속 주시한다.
shoppingListState 는 기존에도 사용하던 쇼핑리스트다.

  1. filterState 와 enum 값이 같은 경우 원래대로 shoppingListState를 반환해준다.
  2. shoppingListState 에서 where 를 해서 필터를 해준다. 스파이시 가 맞을 경우 true 값인 element 들을 아닐 경우 false인 애들을 where로 선택해주면 된다.

spicy 를 골랐을 경우 김치와 라면이 잘나오는 것을 볼수있다. 오늘 뭔가 어려우면서 재밌는 관리를 한거같다.

profile
한 줄 소개

0개의 댓글