본문 바로가기
Flutter

[Flutter] 플러터 - RiverPod 상태관리(5) StateNotifierProvider 맛보기

by s_hoonee 2024. 1. 30.
반응형

Provider, StateProvider, StateNotifierProvider  사용 예시로 이루어진 시리즈

RiverPod 시리즈 5탄입니다. 아래 게시물을 먼저 확인해 주세요.
https://hooninha.tistory.com/89

 

[Flutter] 플러터 - RiverPod 상태관리(4) StateProvider copyWith() 사용해 보기

기존 포스팅 시리즈 3탄입니다. 아래 게시물을 먼저 확인해 주세요. https://hooninha.tistory.com/88 [Flutter] 플러터 - RiverPod 상태관리(3) StateProvider 여러 값 사용해 보기 기존 포스팅 시리즈 3탄입니다. 아

hooninha.tistory.com

이번 포스팅에는  지난 포스팅까지 이어져왔던 stateProvider을 마치고 StateNotifierProvider로 변경해 보겠습니다.

StateNotifierProviderStateNotifier 클래스를 기반으로 하는 프로바이더로, 상태를 변경할 수 있는 StateNotifier를 제공합니다. StateNotifier는 내부적으로 StateProviderNotifier를 결합한 것이며, 이를 통해 불변성을 유지하면서 상태를 업데이트할 수 있습니다.

요약

StateNotifierProvider: StateNotifier 클래스를 기반으로 하며, 상태를 변경하는 Notifier를 제공합니다. StateNotifier 내부에서 상태의 변경을 감지하고 리스너에게 알릴 수 있습니다. 
-> 로직이 들어가면 StateNotifierProvider를 사용하자!

 

실습에 필요한 파일은 두개입니다! (이전 포스팅 코드에서 이어서 작성)

 

1. state.dart 파일에 StateNotifier을 상속받는 MyObjectNotifier 클래스 생성

stateProvider선언 ->  StateNotifierProvider 선언으로 변경

import 'package:flutter_riverpod/flutter_riverpod.dart';

class MyObject {
  final String stringValue;
  final int intValue;

  MyObject({required this.stringValue, required this.intValue});

  MyObject copyWith({String? stringValue, int? intValue}) {
    return MyObject(
      stringValue: stringValue ?? this.stringValue,
      intValue: intValue ?? this.intValue,
    );
  }
}

// -->> 여기 추가해주기 
class MyObjectNotifier extends StateNotifier<MyObject> {
  MyObjectNotifier(MyObject value) : super(value);


// -->>  MyObject의 일부 필드를 업데이트하는 메서드
  void updateMyObject({String? stringValue, int? intValue}) {
    state = state.copyWith(
      stringValue: stringValue,
      intValue: intValue,
    );
  }
}

// StateNotifierProvider로 변경 
final myObjectProvider =
StateNotifierProvider<MyObjectNotifier, MyObject>((ref) {
  return MyObjectNotifier(MyObject(stringValue: '초기값', intValue: 0));
});


// stateProvider
/*final myObjectProvider = StateProvider<MyObject>((ref) {
  return MyObject(stringValue: '초기값', intValue: 0);
});*/
# 문법 설명
StateNotifierProvider<[StateNotifier클래스를 상속받는 클래스], [관리하는 모델]>((ref) {
# 관리하고자 하는 모델의 초기값 (생성자 호출)
  return MyObjectNotifier(MyObject(stringValue: '초기값', intValue: 0));
});

 

 

2. StateNotifier을 상속받는 클래스의 메소드 활용 

read_state_provider.dart 파일에 아래 코드를 작성해줍니다.

 

myObject를 이용해 관리하는 필드들을 꺼냅시다! 

final myObject = ref.watch(myObjectProvider);

 

이제 state값을 불러서 값을 넣어주는 것이 아닌, updateMyObject 함수 내에서 state를 가지고 있기 때문에 내부에서 해결하고 있다는 차이가 있습니다. 훨씬 깔끔해진 것 같아요 ㅎㅎ 

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:gym_app/page/riverpod_page/stateProviders/states.dart';

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

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    /// 이 부분 변경
    final myObject = ref.watch(myObjectProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text('StateNotifierProvider'),
      ),
      body: Center(
        child: Column(
          children: [
            Text(
              myObject.stringValue,
              style: const TextStyle(
                  fontSize: 30, fontWeight: FontWeight.bold, color: Colors.red),
            ),
            Text(
              myObject.intValue.toString(),
              style: const TextStyle(
                  fontSize: 30, fontWeight: FontWeight.bold, color: Colors.red),
            ),
            ElevatedButton(
              onPressed: () {
               /* ref.read(myObjectProvider.notifier).state =
                    myObject.copyWith(stringValue: '호호호',
                    intValue: 100);*/
                ref.read(myObjectProvider.notifier).updateMyObject(
                      intValue: 100,
                      stringValue: '호호호',
                    );
              },
              child: const Text('copyWith 변경 실행'),
            ),
            ElevatedButton(
              onPressed: () {
              /*  ref.read(myObjectProvider.notifier).state = myObject.copyWith(
                  stringValue: '스트링값만',
                );*/
                ref.read(myObjectProvider.notifier).updateMyObject(
                      stringValue: '호호호',
                    );
              },
              child: const Text('copyWith 스트링만 변경 실행'),
            ),
            ElevatedButton(
              onPressed: () {
                ref.refresh(myObjectProvider);
              },
              child: const Text('초기값으로 변경'),
            ),
          ],
        ),
      ),
    );
  }
}