1. 더미 데이터 통신(v1)
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'home_page.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
home_page.dart
import 'package:flutter/material.dart';
import 'home_body.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: HomeBody(),
);
}
}
home_body.dart
import 'package:flutter/material.dart';
import 'package:mockapp/home_repository.dart';
class HomeBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
HomeRepository repo = const HomeRepository();
int one = repo.getOne();
List<int> list = repo.getList();
return Column(
children: [
// 변수 삽입에 {} 유무의 차이 >> 있으면 연산 가능
Text("$one", style: TextStyle(fontSize: 50)),
Expanded(
child: ListView.builder(
itemCount: 4,
itemBuilder: (context, index) {
return ListTile(
leading: Text(("${list[index]}")), title: Text("내용"));
},
),
),
],
);
}
}
future_page.dart
import 'package:flutter/material.dart';
class FuturePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold();
}
}
home_repository.dart
// SRP: 데이터를 가져오는 곳 (휴대폰 디바이스(파일), 휴대폰 DB, Firebase(외부서버), 내서버, 공공데이터서버)
class HomeRepository {
const HomeRepository();
List<int> getList() {
return [1, 2, 3, 4];
}
int getOne() {
return 1;
}
}
2. riverpod
1. 개념
- Flutter에서 상태 관리를 위한 패키지.
- React의 Hooks 개념에서 영감을 받음.
- Provider의 개선 버전으로 더 강력하고 유연함.
2. 특징
- Compile-time 안전성
- 상태 관리 오류를 컴파일 단계에서 감지.
- Null 또는 의존성 누락 문제 감소.
- 의존성 관리
- 프로바이더 간 의존성을 효율적으로 설정 및 관리.
- Global 상태 관리
- 전역 상태를 간단하고 안전하게 관리.
- Lazy Evaluation
- 필요할 때만 상태를 생성하여 성능 최적화.
3. 장점
- 코드 분리: 상태와 UI 분리로 유지보수 용이.
- 테스트 가능: 상태를 쉽게 테스트 가능.
- 유연성: 다양한 상태 관리 패턴 지원.
3. riverpod 없이 비동기 데이터 통신(v2)
변경점
home_repository:
async
와 await
를 사용하여 비동기 통신future_page: future_body생성
main.dart: HomePage() >> FuturePage()
home_repository.dart
class HomeRepository {
const HomeRepository();
// async await 사용 >> Future<리턴타입> 지정
Future<List<int>> getList() async {
List<int> response = await Future.delayed(
// 3초 후에 실행됨!!
Duration(seconds: 3),
() {
return [1, 2, 3, 4];
},
);
return response;
}
Future<int> getOne() async{
int response = await Future.delayed(
Duration(seconds: 3),
() {
return 5;
},
);
return response;
}
}
future_page.dart
import 'package:flutter/material.dart';
import 'future_body.dart';
// reiverpod 없이 데이터 가져오기
class FuturePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBody(),
);
}
}
future_body.dart (생성됨)
import 'package:flutter/material.dart';
import 'package:mockapp/home_repository.dart';
class FutureBody extends StatelessWidget {
HomeRepository repo = const HomeRepository();
@override
Widget build(BuildContext context) {
return Column(
children: [
// future >> Future를 반환하는 값넣음
FutureBuilder(
future: repo.getOne(),
// snapshot == 반환값
builder: (context, snapshot) {
// 반환값이 있으면 값 반환
if (snapshot.hasData) {
return Text("1", style: TextStyle(fontSize: 50));
} else {
// 없으면 기다리기
return CircularProgressIndicator();
}
},
),
Expanded(
child: ListView.builder(
itemCount: 4,
itemBuilder: (context, index) {
return ListTile(
leading: Text(("${index + 1}")), title: Text("내용"));
},
),
),
],
);
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mockapp/future_page.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FuturePage(),
);
}
}
4. riverpod으로 비동기 데이터 통신(v3)
변경점
main: FuturePage() >> HomePage()
home_body: StatelessWidget >> ConsumerWidget
home_page_vm: reiverpod Provider
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'home_page.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
home_page.dart
import 'package:flutter/material.dart';
import 'home_body.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: HomeBody(),
);
}
}
home_body.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mockapp/home_page_vm.dart';
class HomeBody extends ConsumerWidget {
@override
Widget build(BuildContext contextm, WidgetRef ref) {
int? one = ref.watch(homeProvider);
if (one == null) {
return Center(child: CircularProgressIndicator());
} else {
return Column(
children: [
Text("$one", style: TextStyle(fontSize: 50)),
Expanded(
child: ListView.builder(
itemCount: 4,
itemBuilder: (context, index) {
return ListTile(
leading: Text(("${index + 1}")), title: Text("내용"));
},
),
),
],
);
}
}
}
home_page_vm.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mockapp/home_repository.dart';
final homeProvider = NotifierProvider<HomePageVM, int?>(() {
return HomePageVM();
});
class HomePageVM extends Notifier<int?> {
HomeRepository repo = const HomeRepository();
@override
int? build() {
// 상태 초기화 코드 >> build에 작성해두는게 좋음 >> 어차피 한번 실행해야함
getOne();
// 상태 null 임시 초기화
return null;
}
Future<void> getOne() async {
int one = await repo.getOne();
state = one;
}
}


의존 관계 차이
Spring MVC: Controller > Service > Repository
Flutter MVVM: View > ViewModel > Repository
Share article