1) ๊ฐ์
ํ๋ฌํฐ๋ฅผ ์ ๋ฌธํ ์ง ์ด๋๋ง 3๋ ์ฐจ๊ฐ ๋์ด๊ฐ๋ค.
๊ทธ๋์ ์ํ๊ด๋ฆฌํด๋ก์จ Provider๋ฅผ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํด ์์์ง๋ง ์ธ์ ๊ฐ๋ Deprecated ๋๋ค๋ Provider์ ์ฐฝ์์์ ๋ง์ ์ถฉ๊ฒฉ์ ๋ฐ๊ฒ ๋์๋ค. ๋ค๋ฅธ ์ํ๊ด๋ฆฌํด์ ์ตํ์ผ ๋ ๋๊ฐ ๋ ๊ฒ ๊ฐ์ ์์๋ณด๋ ๋์ค GetX์ BLoC์ ๋์ ๋ค์ด๊ฒ ๋์๋๋ฐ
GetX์ ๊ฒฝ์ฐ์ 10๊ฐ์์งธ ํจํค์ง ์ ๋ฐ์ดํธ๊ฐ ์ด๋ค์ง์ง ์๊ณ ์๊ณ BLoCํจํด์ ๊ฒฝ์ฐ๋ ๊ฐ๋จํ ํ๋ก์ ์ ์ด์ธ๋ฆฌ์ง ์์ผ๋ฉฐ ๋์ด๋๊ฐ ์ด๋ ต๊ธฐ ๋๋ฌธ์ ๋ง์ง๋ง์ผ๋ก Provider์ ๊ณ์น์์ธ RiverPod์ ์๊ฒ ๋์๋ค.
RiverPod ์ Provider์ ์ฒ ์์์ ์์๋ง ๋ฐ๋ ๋จ์ด์ด๋ฉฐ
Provider์์ ์ปดํ์ผ๋ฌ ์ค์ ๋ฐ์ํ๋ ์ค๋ฅ, ์ฌ๋ฌ ๋ฌธ์ ์ ๋ค์ ์ต๋ํ ๊ฐ์ ํ์ฌ RiverPod์ผ๋ก ๋ฐฐํฌ๊ฐ ๋์์๋ค.
์ฐ์ ํจํค์ง๋ถํฐ ์ค์ ํ๋๋ก ํ์
2) ์ค์น
์ง์ pub.dev ์์ ๋ฒ์ ์ ์ง์ ํ์ฌ pubspec.yaml์ ์ถ๊ฐํ๋ ๋ฐฉ์์ ์ฌ์ฉํ๊ฑฐ๋
https://pub.dev/packages/riverpod
์๋์ ๋ช ๋ น์ด๋ก ๊ฐ๋จํ๊ฒ ์ถ๊ฐํ๋๋ก ํ์.
flutter pub add flutter_riverpod
3) ์ฝ๋์์ฑ
์ฐ์ ์ฐ๋ฆฌ๋ 1๋ฒ ํ๋ฉด์์ FAB๋ฒํผ์ ํด๋ฆญํ๋ฉด ์ซ๊ฐ ์ฌ๋ผ๊ฐ๊ณ 2๋ฒ ํ๋ฉด์์๋ 1๋ฒ ํ๋ฉด์์ ๋ดค๋ ์ซ์๋ฅผ ๋๊ฐ์ด ์ฌ๋ฆด ์ ์๋๋ก ํ๋ ์ฑ์ ๋ง๋ค๋๋ก ํ ๊ฒ์ด๋ค.
riverpod ์ฌ์ฉ์ ํ๊ธฐ ์ํด์ ๋จผ์ main.dart ํ์ผ์ runApp๋ถ๋ถ์ ๋ค์๊ณผ ๊ฐ์ด ์์ ํด์ค์ผ ํ๋ค.
main.dart
void main() {
runApp(
ProviderScope(
child: MainApp(),
),
);
}
count_state.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
final countState = StateNotifierProvider<CountNotifier, int>((ref) => CountNotifier());
class CountNotifier extends StateNotifier<int> {
CountNotifier() : super(0);
void increment() => state++;
}
์์ ์ฝ๋์ฒ๋ผ count_state.dart ํ์ผ์ ๋ง๋ ํ ๋ด๋ถ์ ์ฝ๋๋ฅผ ์์ฑํ๋๋ก ํ๋ค.
์ฌ๊ธฐ์ final countState ๋ณ์๋ StateNotifierProvider์ ๊ฐ์ฒด๋ก App ์์ค์ ์ ์ญ ๋ณ์๋ก ์ฌ์ฉ๋ ์ ์๋ค.
ํด๋น ๊ฐ์ฒด์๋ StateNotifier๋ก๋ถํฐ ์์๋ฐ์ CountNotifier ๊ฐ์ฒด์ int ๊ฐ์ฒด๋ฅผ (๋ค๋ฅธ ํด๋์คํ์ผ, ์๋ฅผ ๋ค์ด User๋ชจ๋ธ ํด๋์ค๋ฅผ ์ฌ์ฉํ ์ ์๋ค) ๋ด๊ฒ ๋๋ค. ์ด๋ ๊ฒ ํ ๊ฐ์ฒด๊ฐ ๋ฌด๋ฆฌ๋ฅผ ์ด๋ฃจ๋ ๋ชจ์ต์ ํ์ฌ์ RiverPod์ด๋ผ๋ ๋จ์ด๊ฐ ์์ฑ๋ ๊ฒ ์๋๊น ๋ผ๋ ๋ํผ์ ์ ๋จ๊ฒจ๋ณธ๋ค.
CountNotifier ํด๋์ค ๋ด๋ถ์๋ ์์ฑ์๋ฅผ 0์ผ๋ก ์ด๊ธฐํํ๋ ๊ธฐ๋ฅ๊ณผ increment() ๋ฉ์๋๋ฅผ ํตํด int๋ณ์๋ฅผ ++ ํด์ฃผ๋ ์ญํ ์ ์ํํ๊ณ ์๋ค.
๋ค์์ ์ฒซ ๋ฒ์งธ ํ๋ฉด์ผ๋ก ๋ณด์ฌ์ค ์ฝ๋๋ฅผ ๋จ๊ธฐ๋๋ก ํ๊ฒ ๋ค.
first_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_test/screens/second_screen.dart';
import 'package:riverpod_test/states/counte_state.dart';
class FirstScreen extends ConsumerStatefulWidget{
@override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends ConsumerState<FirstScreen> {
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
final int count = ref.watch(countState);
print('onBuild');
return Scaffold(
appBar: AppBar(
title: Text('FirstScreen'),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: _onPressedFAB,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
count.toString(),
style: TextStyle(fontSize: 32),
),
ElevatedButton(onPressed:_onPressedGoToSecondButton, child: Text('Go to Second'))
],
),
),
);
}
void _onPressedFAB() {
final CountNotifier counteNotifier = ref.read(countState.notifier);
counteNotifier.increment();
}
void _onPressedGoToSecondButton(){
Navigator.push(context,MaterialPageRoute(builder: (context)=>SecondScreen()));
}
}
์ฌ๊ธฐ์ ์ฒซ ๋ฒ์งธ๋ก ๋ณด์ด๋ ์ฐจ์ด์ ์
StatefulWidgetํด๋์ค์ ์์ ๋ถ๋ถ์ด๋ค.
๊ธฐ์กด์๋ FirstScreen์ StatefulWidget์ผ๋ก ์ ์ธํ ๋
class FirstScreen extends StatefulWidget{
@override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
@override
Widget build(BuildContext context){
return ...
}
}
์ด๋ฐ ๋ชจ์ต์ผ๋ก ์ ์ธํ์๋ค.
ํ์ง๋ง RiverPod์ ๋ณ๋๋ก ์ํ๊ด๋ฆฌ ๋ถ๋ชจํด๋์ค๋ก ConsumerStatefulWidget์ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ
StatefulWidget๊ณผ๋ ํฐ ์ฐจ์ด๊ฐ ์๋ค.
๋ง์ฝ RiverPod์ผ๋ก StatefulWidget์ ์์ฑํ ๊ฒฝ์ฐ ์๋์ ๋ชจ์ต์ผ๋ก ์์ํ๊ฒ ๋ ๊ฒ์ด๋ค.
class FirstScreen extends ConsumerStatefulWidget {
@override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends ConsumerState<FirstScreen> {
@override
Widget build(BuildContext context){
return ...
}
}
๊ทธ๋ค์์ผ๋ก ๋ด์ผ ํ ๋ถ๋ถ์ build๋ฉ์๋ ๋ถ๋ถ์ด๋ค.
๊ธฐ์กด์ StatefulWidget์์์ build ๋ฉ์๋๋ ๋ณดํต BuildContext๋ง ์ฌ์ฉํ๋ค.
๊ทผ๋ฐ RiverPod์ StatefulWidget์ WidgetRef๋ฅผ ์ฌ์ฉํ๊ณ ์๋ ๊ฑธ ๋ณด๊ณ ์๋ค.
์ฐ๋ฆฐ WidgetRef๋ฅผ ํตํด Provider๋ฅผ ํธ์ถํ๊ณ UI๊ฐฑ์ ์ ํ๊ณ ์ํ๋ฅผ ๊ด๋ฆฌํ ์ ์๊ฒ ๋๋ค.
final int count = ref.watch(countState);
ref์์์ watch๋ฅผ ํตํด ์ด์ ์ ์ฐ๋ฆฌ๊ฐ ์์ฑํด ๋ countState์์ int๋ณ์๋ฅผ ๊ฐ์ ธ์ฌ ์๊ฐ ์๊ฒ ๋๋ค.
final CountNotifier counteNotifier = ref.read(countState.notifier);
counteNotifier.increment();
๊ทธ๋ฆฌ๊ณ ref์์์ read๋ฅผ ํตํด countState์ Notifier๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๊ฒ ๋๊ณ ์ด๋ฅผ ํตํด ๊ฐ์ ์ปจํธ๋กคํ ์๊ฐ ์๊ฒ ๋๋ค.
๋ง์ฝ Notifier๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ๋๋ค๋ฉด UI๊ฐ ์๋์ผ๋ก rebuild ๊ฐ ๋๊ฒ ๋๋ค.
๋ค์์ ๋ ๋ฒ์งธ ํ๋ฉด์์ ์ซ์๋ฅผ ๋ณ๊ฒฝํ๊ธฐ ์ํด ์๋ก์ด ๋ ๋ฒ์งธ ํ๋ฉด ํ์ผ์ ์์ฑํ๋๋ก ํ๊ฒ ๋ค.
second_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_test/states/counte_state.dart';
class SecondScreen extends ConsumerWidget {
const SecondScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context,WidgetRef ref) {
final CountNotifier countNotifier = ref.read(countState.notifier);
final int count = ref.watch(countState);
return Scaffold(
appBar: AppBar(
title: Text('SecondScreen'),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: (){
countNotifier.increment();
},
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
count.toString(),
style: TextStyle(fontSize: 32),
),
],
),
));
}
}
์ด๋ฒ์ SecondScreen์ ๋ถ๋ชจํด๋์ค๋ CunsumerWidget์ธ๋ฐ StatelessWidget์ ๊ฐ์ ์ญํ ์ ์ํํ๋ฉฐ ref๋ฅผ ์ ๊ณตํ๊ธฐ๋ ํ๋ค.
์ฌ๊ธฐ์๋ ๋ง์ฐฌ๊ฐ์ง๋ก ref.watch()๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋๋ก ํ๊ณ
ref.read()๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๋ ๋ชจ์ต์ ๋ณผ ์ ์๋ค.
์ฌ๊ธฐ๊น์ง RiverPod์ ์์ฃผ ๊ธฐ๋ณธ์ ์ธ ์ํ๊ด๋ฆฌ์ ๋ํด ์์๋ณด์๊ณ , ๋ค์์ ์กฐ๊ธ ๋ ๋ค์ํ ๊ธฐ์ ์ ๋ค๋ค๋ณด๋๋ก ํ ๊ฒ์ด๋ค.