Getx 만 사용해오다가 프로젝트에서 Riverpod을 사용하게되어서 공부하였다.
Getx는 사용하기 편리하고 자유성이 높은 프레임워크지만, 여러가지 이슈가 있고 대응이 느리다고한다.
따라서 Getx에만 너무 의존하지 말고, Provider/Riverpod/Bloc 중 하나정도는 더 공부하는 것이 좋다.
flutter Riverpod 이란 "반응형 캐싱 및 데이터 바인딩 프레임워크" 이다.
Riverpod과 Provider의 개발자는 같은 개발자이며, Provider의 문제점을 해결하여 만든 것이 Riverpod이라고 한다.
Install
flutter pub add flutter_riverpod
Provider 종류
Provider은 상태관리를 할 데이터 변수를 정의하는 것이다.
1. Provider
Provider은 read_only Provider이다.
final countProvider = Provider<int>((ref) {
return 0;
});
2. StateProvider
StateProvider은 상태를 변경할 수 있는 Provider이다. 하지만 다른 로직과 함께 사용할 수는 없다.
final counterProvider = StateProvider<int>((ref) {
return 0;
});
3. StateNotifierProvider
이게 아마 제일 자주 사용할 Provider일 것이다.
데이터의 상태관리 뿐만 아니라 로직도 추가하여 사용할 수 있다.
final todoListProvider = StateNotifierProvider<TodoList, List<String>>((ref) {
return TodoList();
});
class TodoList extends StateNotifier<List<String>> {
TodoList() : super([]);
void add(String item) {
print("state : $state");
state = [...state, item]; // state에는 prev 값이 들어가네.
}
}
Riverpod을 사용하여 간단하게 Todo 리스트를 추가하고 삭제하는 기능을 구현해보았다.
// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'home.dart';
void main() {
runApp (const ProviderScope(child: MainApp()));
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Home()
);
}
}
Riverpod을 사용하기 위해서는 runApp내부를 ProviderScope로 감싸주어야한다.
// provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
final todoListProvider = StateNotifierProvider<TodoList, List<String>>((ref) {
return TodoList();
});
class TodoList extends StateNotifier<List<String>> {
TodoList() : super([]);
void add(String item) {
print("state : $state");
state = [...state, item];
}
void remove(String item) {
state = state.where((element) => element != item).toList();
}
}
Provider을 별도의 파일에 정의해보았다.
Todo리스트를 추가하거나 삭제하는 로직이 필요하기 때문에 StateNotifierProvider와 StateNotifier을 사용하였다.
// home.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'provider.dart';
class Home extends ConsumerWidget {
Home({super.key});
TextEditingController inputTodo = TextEditingController();
@override
Widget build(BuildContext context, WidgetRef ref) {
final todo = ref.watch(todoListProvider);
ref.listen(todoListProvider, (prev, next) {
print("현재상태 : $prev , $next");
});
return SafeArea(
child: Scaffold(
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Todo",
style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.green[400]!),
borderRadius: BorderRadius.circular(10)),
width: MediaQuery.of(context).size.width * 0.7,
child: TextField(
controller: inputTodo,
decoration: InputDecoration(border: InputBorder.none),
)),
ElevatedButton(
onPressed: () {
ref.watch(todoListProvider.notifier).add(inputTodo.text);
},
child: Text("추가"))
],
),
SizedBox(
height: 30,
),
...List.generate(
todo.length,
(index) => Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.only(left: 8.0, top: 8),
child: Text(
todo[index],
style: TextStyle(
fontSize: 17,
),
),
),
TextButton(
onPressed: () {
ref
.read(todoListProvider.notifier)
.remove(todo[index]);
},
child: Text("삭제"))
],
)))
],
),
),
),
);
}
}
Riverpod을 사용할 땐 StatelessWidget 이나 StatefulWidget을 사용하지 않고 ConsumerWidget을 사용한다.
Consumer, ConsumerStatefulWidget도 있지만 보편적으로 ConsumerWidget을 사용하는 것 같다.
ConsumerWidget을 사용하면 Widget build 부분에 Widget ref 를 추가해준다.
ref 객체는 위젯에서 Provider에 접근할 수 있도록 해준다.
접근 하는 방법에는 watch, read, listen이 있는데 공식문서에서 read와 listen 보다 watch를 사용하는 것을 권장하고 있다.
ref.watch는 provider의 변화된 값을 감지하고, Widget을 재빌드한다.
참고자료
https://velog.io/@leeeeeoy/Flutter-Riverpod-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0-1
[Flutter] Riverpod 사용해보기 #1
이 글은 공식 문서, 유튜브 강의와 블로그를 참고하여 정리한 글입니다.
velog.io
'Flutter' 카테고리의 다른 글
[Flutter] 플러터로 달력 구현하기 (flutter_calendar_carousel) (0) | 2024.01.02 |
---|---|
MVVM 패턴이란? MVC 패턴과의 차이? (1) | 2023.12.31 |
[Flutter] Future과 FutureBuilder를 이용한 비동기 작업 (0) | 2023.08.31 |
[Flutter] WebView(웹뷰)를 이용한 웹페이지 연결하는 법 -webview_flutter (0) | 2023.08.03 |
[Flutter] 앱에서 인공지능 모델 활용하기 - tflite_flutter (0) | 2023.07.30 |