1. RiverPod 란?
RiverPod은 플러터에서 위젯의 상태를 관리하는 라이브러리로, 단순한 상태 관리 이상으로 의존성을 관리하고 필요에 따라 상태를 제공하는 기능을 제공한다. 이를 통해 앱의 모든 부분이 필요한 데이터에 쉽게 액세스할 수 있다.
Stateful 위젯의 상태가 변경되면, 해당 Stateful 위젯의 하위 위젯들은 전체가 rebuild 된다.
만약 두 Stateful 위젯이 서로 상태를 공유해야 한다면 , 공유하고 있는 가장 상위의 부모 위젯이 Stateful 위젯이 되어야 한다.
그림과 같이 가장 가까운 부모 위젯이 Stateful 위젯이 되어야 한다.
이렇게 되면 단점이 있다.
- 부모 위젯에서 상태와 메서드를 전달해야하기 때문에 트리가 깊어지면 매번 전달하는 귀찮음이 있다.
- 부모가 rebuild가 되면 하위의 자식 위젯 전체가 다시 그려진다. 그래서 트리의 설계를 매우 잘해야 한다.
이를 해결하기 위한 방법이 RiverPod 라이브러리로, RiverPod 라이브러리는 상태를 외부에서 관리하기 때문에 불필요한 rebuild가 일어나지 않는다.
2. Provider
Provider는 상태를 공유하고 액세스하는 것을 단순화하여 개발자가 더 쉽게 상태 관리를 할 수 있도록 도와준다.
Provider 는 지속적으로 상태 변화를 관찰하지 않고 최초 한번만 관찰한다. 최초 생성 시에 상태값을 가지게 되며, 해당 상태값을 통해 그림을 그린다. 이후 상태값이 변경된다 하더라도 그림은 다시 그려지지 않는다.
기본 설정을 한다.
main.dart
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:riverpod_test/todo_page.dart'; void main() { //riverpod 을 사용하기 위해서는 ProviderScope 로 MyApp을 설정해야 한다. runApp(ProviderScope(child: const MyApp())); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: TodoPage(), ); } }
todo_page.dart
import 'dart:ffi'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:riverpod_test/todo.dart'; class TodoPage extends ConsumerWidget { // 위젯을 ConsumerWidget 으로 만들면 Provider에 접근할 수 있다. const TodoPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { //WidgetRef 필요 Todo todo = ref.read(todoProvider); // read 는 상태값을 한번만 수신할 떄 사용 return Scaffold( body: Center( child: Text( "완료 : ${todo.isCompleted}, 내용 : ${todo.description}", style: TextStyle(fontSize: 30), ), ), ); } }
Provider 를 사용하면 외부 클래스에 저장된 데이터에 접근해 화면에 출력할 수 있다.
3. StateNotifierProvider
StateNotifierProvider 는 상태가 변경될 때 변경을 감지하여 참조한 위젯에게 알려주며, 위젯이 상태를 구독할 경우 상태값이 변경될 때 마다 해당 위젯이 다시 그려진다.
fruit_store.dart
import 'package:flutter_riverpod/flutter_riverpod.dart'; // 데이터 String data = "사과"; // 창고 class FruitVM extends StateNotifier<String> { FruitVM(super.state); void changeData() { state = "딸기"; } } // 창고 관리자 final fruitProvider = StateNotifierProvider<FruitVM, String>( (ref) { return FruitVM(data); }, );
main.dart
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '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) { // 1. 창고 데이터 String data = ref.watch(fruitProvider); // 2. 창고 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("딸기상태로 변경")) ], ), ), ); } }
data 는 사과 상태로 시작한다.
버튼을 누르면 상태값이 변경되면서 그림도 다시 그려진다.
Share article