반응형
Provider, StateProvider, StateNotifierProvider 사용 예시로 이루어진 시리즈
RiverPod 시리즈 5탄입니다. 아래 게시물을 먼저 확인해 주세요.
https://hooninha.tistory.com/89
이번 포스팅에는 지난 포스팅까지 이어져왔던 stateProvider을 마치고 StateNotifierProvider로 변경해 보겠습니다.
StateNotifierProvider는 StateNotifier 클래스를 기반으로 하는 프로바이더로, 상태를 변경할 수 있는 StateNotifier를 제공합니다. StateNotifier는 내부적으로 StateProvider와 Notifier를 결합한 것이며, 이를 통해 불변성을 유지하면서 상태를 업데이트할 수 있습니다.
요약
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('초기값으로 변경'),
),
],
),
),
);
}
}
'Flutter' 카테고리의 다른 글
[Flutter] 플러터 - ListView vs ListView.builder 활용 및 차이점 (0) | 2024.02.05 |
---|---|
[Flutter] 플러터 - Visibility vs Opacity 위젯 숨기기와 투명도 조절 (0) | 2024.02.05 |
[Flutter] 플러터 - RiverPod 상태관리(4) StateProvider copyWith() 사용해 보기 (1) | 2024.01.30 |
[Flutter] 플러터 - RiverPod 상태관리(3) StateProvider 여러 값 사용해 보기 (0) | 2024.01.30 |
[Flutter] 플러터 - RiverPod 상태관리(2) StateProvider 단일 값 사용해 보기 (0) | 2024.01.30 |