3. stateNotifierProvider

shin·2023년 3월 13일
0

Flutter riverpod

목록 보기
3/6
  • StateProvider와 마친가지로 UI에서 직접적으로 데이터를 변경할 수 있도록 하고 싶을 때 사용한다.
  • 복잡한 형태의 데이터 관리가 가능하다.(클래스의 메소드를 이용한 상태관리)
  • StateNotifier를 상속한 클래스를 반환한다.
  • stateNotifierProvider를 사용하기 전에 몇가지 값들이 들어있는 모델을 생성했다.
class ShoppingItemModel {
  // 이름
  final String name;
  // 갯수
  final int quantity;
  // 구매했는지
  final bool hasBought;
  // 매운지
  final bool isSpacy;

  ShoppingItemModel({
    required this.name,
    required this.quantity,
    required this.hasBought,
    required this.isSpicy,
  });

}

생성하기

  • 우선 코드를 작성할 state_notifier_provider.dart 파일을 생성한다
  • stateNotifierProvider는 class로 시작한다.
  • 절대적으로 StateNotifier를 상속받고 무조건 상태 관리할 타입이 어떤 타입인지 지정해 줘야 한다.
  • 생성자를 생성하고 super() 값에 처음에 어떤 값을 초기화 해줄지 넣어줘야 한다.
class ShoppingListNotifier extends StateNotifier<List<ShoppingItemModel>> {
  ShoppingListNotifier()
      : super([]);
      }

  • 앞에서 생성한 model를 참고해서 초기값을 넣어줬다.
  • stateProvider와 달리 class안에서 복잡한 상태를 관리하기 때문에 메소드를 사용해서 값들을 변경시키는 작업을 해야한다. 예제에서는 구매한 것을 true로 변경하는 메소드를 작성해서 사용한다.
  • ShoppingListNotifierProvider로 사용할 때 StateNotifierProvider를 사용한다. 제너릭에는 2가지 값이 들어간다. 첫번째 값은 어떤 Notifier를 사용하는 지에 대한 값이 들어가고 두번째 값은 ShoppingListNotifier가 관리하는 state의 타입이 들어가게 된다. 그리고 반환 값에는 ShoppingListNotifier()를 넣어주면 된다.
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 
    // 여기서 state는 super 생성자에 첫번째 파라미터를 의미하고 StateNotifier에서 기본적으로 제공하는 값이다. 
        .map((e) => e.name == name
            ? ShoppingItemModel(
                name: e.name,
                quantity: e.quantity,
                hasBought: !e.hasBought,
                isSpicy: e.isSpacy,
              )
            : e)
        .toList();
  }
}

사용하기

  • stateProvider를 사용했던 것과 같이 사용하면 된다.
class StateNotifierProviderScreen extends ConsumerWidget {
  const StateNotifierProviderScreen({Key? key}) : super(key: key);

  
  Widget build(BuildContext context, WidgetRef ref) {
    final List<ShoppingItemModel> state = ref.watch(shoppingListProvider);
    // watch를 하면 바로 state가 반환된다.

    return DefaultLayout(
      title: 'StateNotifierProvider',
      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(),
      ),
    );
  }
}
  • 무언가 액션을 취했을 때 단발적으로 실행하는 것은 ref.read를 사용한다.
  • shoppingListProvider에서 값을 업데이트하기 위해서는 .notifier를 해줘야한다.

0개의 댓글