
1. StateNotifierProvider
- Flutter의 provider 패키지에 있는 클래스 중 하나
- Riverpod 패키지에서 제공하는 클래스
- 상태 관리를 위한 Provider 패키지의 대안 중 하나
- Flutter 위젯 트리의 일부에 값을 제공
- 해당 값이 변경될 때 의존하는 위젯을 자동으로 업데이트하는 데 사용
- 일반적으로 StateNotifier와 함께 사용 / 상태 컨테이너와 알림 기능을 결합한 클래스
- 데이터가 변경되고 다시 그림이 그려짐
- watch(이벤트 감지)를 read로 바꾸면 Provider와 같이 사용할 수 있음
2. 실습하기
flutter_riverpod: 2.5.1

import 'package:flutter_riverpod/flutter_riverpod.dart';
//1. 창고 데이터 : 상태값
String data = "사과";
//2. 창고 : 상태 변경(메서드), VIEW에 필요한 데이터 커스터마이징
class FruitVM extends StateNotifier<String> {// 상태가 변경되면 화면에 알려줌
FruitVM(super.state);
void changeData(){ // 상태를 변경할 메서드
state = "딸기";
}
//3. 창고 관리자 : 창고에 IO(접근)하게 해줌
//창고 이름, 창고 상태
final fruitProvider = StateNotifierProvider<FruitVM, String>((ref) {
return FruitVM("사과"); // watch or read 할때 호출됨
});

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(
ProviderScope(
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FruitPage(),
);
}
}
class FruitPage extends ConsumerWidget {
const FruitPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"data : 사과",
style: TextStyle(fontSize: 30),
),
ElevatedButton(
onPressed: () {},
child: Text("딸기로 상태 변경"),
),
],
),
),
);
}
}

- 창고에 데이터 넣어야 상태가 됨!!
import 'package:flutter_riverpod/flutter_riverpod.dart';
//1. 창고 데이터 : 상태값
String date = "사과";
//2. 창고 : 상태 변경(메서드), VIEW에 필요한 데이터 커스터마이징
class FruitVM extends StateNotifier<String> {
// 상태가 변경되면 화면에 알려줌
FruitVM(super.state); // 상태값을 "사과"로 초기화
void changeData() {
// 상태를 변경할 메서드
state = "딸기";
}
}
//3. 창고 관리자 : 창고에 IO(접근)하게 해줌
//창고 이름, 창고 상태
final fruitProvider = StateNotifierProvider<FruitVM, String>((ref) {
return FruitVM(date);
});
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(
ProviderScope(
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FruitPage(),
);
}
}
class FruitPage extends ConsumerWidget { // 컨슈머
const FruitPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text( // 상태값 -> 그림이 그려지는 곳
"data : 사과",
style: TextStyle(fontSize: 30),
),
ElevatedButton( // 상태값을 바꾸는 곳
onPressed: () {},
child: Text("딸기로 상태 변경"),
),
],
),
),
);
}
}
3. Provier와 다른 점!
- 상태를 바로 리턴해줌
- 창고를 리턴할 때 notifier이 필요함!

- 값만 변경됨
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod_02/fruit_store.dart';
void main() {
runApp(
ProviderScope(
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FruitPage(),
);
}
}
class FruitPage extends ConsumerWidget {
// 컨슈머
const FruitPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// 상태를 바로 리턴하는 방법
String data = ref.read(fruitProvider);
// 창고를 리턴하는 방법
FruitVM vm = ref.read(fruitProvider.notifier);
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
// 상태값 -> 그림이 그려지는 곳
"data : ${data}",
style: TextStyle(fontSize: 30),
),
ElevatedButton(
// 상태값을 바꾸는 곳
onPressed: () {
vm.changeData();
print(vm.state);
},
child: Text("딸기로 상태 변경"),
),
],
),
),
);
}
}


- 다시 그려짐
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod_02/fruit_store.dart';
void main() {
runApp(
ProviderScope(
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FruitPage(),
);
}
}
class FruitPage extends ConsumerWidget {
// 컨슈머
const FruitPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// 상태를 바로 리턴하는 방법
String data = ref.read(fruitProvider);
// 창고를 리턴하는 방법
FruitVM vm = ref.read(fruitProvider.notifier);
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
// 상태값 -> 그림이 그려지는 곳
"data : ${data}",
style: TextStyle(fontSize: 30),
),
ElevatedButton(
// 상태값을 바꾸는 곳
onPressed: () {
vm.changeData();
print(vm.state);
},
child: Text("딸기상태로 변경"),
),
],
),
),
);
}
}

4. 실습하기2
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod_02/fruit_store.dart';
void main() {
runApp(ProviderScope(child: const MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FruitPage(),
);
}
}
class FruitPage extends StatelessWidget {
const FruitPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
MyConsumer1(), // 구독
MyConsumer2(), // 구독
MyConsumer3(), // 구독안함
MyPublisher(), // 출판
],
),
),
);
}
}
class MyPublisher extends ConsumerWidget {
const MyPublisher({
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
print("MyPublisher 빌드됨");
// 1. 출판
FruitVM vm = ref.read(fruitProvider.notifier);
return ElevatedButton(
onPressed: () {
vm.changeData();
},
child: Text("딸기상태로 변경"));
}
}
class MyConsumer1 extends ConsumerWidget {
const MyConsumer1({
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
print("MyConsumer1 빌드됨");
String data = ref.watch(fruitProvider);
return Text("data : ${data}", style: TextStyle(fontSize: 30));
}
}
class MyConsumer2 extends ConsumerWidget {
const MyConsumer2({
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
print("MyConsumer2 빌드됨");
String data = ref.watch(fruitProvider);
return Text("data : ${data}", style: TextStyle(fontSize: 30));
}
}
class MyConsumer3 extends StatelessWidget {
const MyConsumer3({
super.key,
});
@override
Widget build(BuildContext context) {
print("MyConsumer3 빌드됨");
return Text("data : 사과", style: TextStyle(fontSize: 30));
}
}


5. 실습하기3
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod_02/fruit_store.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FruitPage(),
);
}
}
class FruitPage extends StatefulWidget {
const FruitPage({super.key});
@override
State<FruitPage> createState() => _FruitPageState();
}
class _FruitPageState extends State<FruitPage> {
String data = "사과";
void changeData() {
data = "딸기";
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
MyConsumer1(data), // 구독
MyConsumer2(data), // 구독
MyConsumer3("사과"), // 구독안함
MyPublisher(changeData), // 출판
],
),
),
);
}
}
class MyPublisher extends StatelessWidget {
final changeData;
MyPublisher(this.changeData);
@override
Widget build(BuildContext context) {
print("MyPublisher 빌드됨");
return ElevatedButton(
onPressed: () {
changeData();
},
child: Text("딸기상태로 변경"));
}
}
class MyConsumer1 extends StatelessWidget {
final data;
MyConsumer1(this.data);
@override
Widget build(BuildContext context) {
print("MyConsumer1 빌드됨");
return Text("data : ${data}", style: TextStyle(fontSize: 30));
}
}
class MyConsumer2 extends StatelessWidget {
final data;
MyConsumer2(this.data);
@override
Widget build(BuildContext context) {
print("MyConsumer2 빌드됨");
return Text("data : ${data}", style: TextStyle(fontSize: 30));
}
}
class MyConsumer3 extends StatelessWidget {
final data;
MyConsumer3(this.data);
@override
Widget build(BuildContext context) {
print("MyConsumer3 빌드됨");
return Text("data : ${data}", style: TextStyle(fontSize: 30));
}
}


Share article