Riverpod을 활용한 UI 상태관리
2024-02-25 19:56 | Flutter
Flutter는 선언형 UI 프로그래밍 방식이기 때문에 상태 관리가 매우 중요하며, Riverpod을 이용하면 상태 관리를 효율적으로 할 수 있고 데이터 바인딩을 통해 UI를 자동으로 업데이트 할 수 있다.
Riverpod이란?
Riverpod은 InheritedWidget과 비슷한 동작을 하는 새로운 매커니즘으로 재구현한 상태 관리 패키지이다. Riverpod은 리액티브 캐싱, 데이터 바인딩 프레임워크이며 리액티브 캐싱과 데이터 바인딩 기능의 정의는 아래와 같다.
-
리액티브 캐싱(Reactive Caching) : 데이터를 비동기적으로 계산 할 때 캐싱하여 해당 데이터가 필요한 모든 곳에서 쉽게 접근할 수 있도록 하는 기술이다. Riverpod에서는 Provider를 이용하여 상태를 지속적으로 캐시하고 노출함으로써 데이터를 쉽게 공유하고 동기화할 수 있다. 예를 들어, 처음 데이터를 가져온 뒤에는 동일한 데이터를 다른 컴포넌트에서 다시 가져올 필요 없이, 이미 캐시된 데이터를 활용하여 중복 호출을 줄이며 상태를 효율적으로 관리하고 성능을 향상시킬 수 있다.
-
데이터 바인딩(Data Binding) : UI와 데이터를 결합하는 기술로 데이터의 변경에 따라 UI를 자동으로 변경하도록 해준다. Riverpod을 이용하면 상태를 나타내는 Provider 및 ref 객체의 watch 메소드를 통해서 상태의 변경을 관찰하여 UI가 자동으로 업데이트되도록 할 수 있다. 즉, MVVM 패턴을 구현할 수 있다.
ProviderScope
ProviderScope는 정의한 Provider의 상태를 저장하는 위젯이다. Provider가 정의될 때 ProviderScope 내부적으로 ProviderContainer 인스턴스를 생성한다.
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(
const ProviderScope(
child: FlutterRiverpodTodoApp(),
),
);
}
ref 객체 얻기
프로바이더로 부터 "ref" 객체 얻기
프로바이더를 읽기전에 "ref" 객체를 얻어야 한다. "ref"는 프로바이더간에 상호작용을 도와주고 위젯이나 다른 프로바이더에서 얻을 수 있다.
위젯에서 "ref" 객체 얻기
위젯들은 "ref" 파라미터를 가지고 있지 않으므로 Riverpod에서는 위젯에서 "ref" 객체를 얻기위한 솔루션을 제공합니다. 기본적으로 위젯을 생성할 때 상속받는 StatelessWidget 대신 ConsumerWidget으로 상속받기 가장 기본적으로 위젯에서 "ref" 객체를 얻기위한 방법입니다. ConsumerWidget은 기본적으로 StatelessWidget 과 동일합니다. 차이가 있다면 build메소드에 추가적으로 "ref" 객체를 받습니다.
-StatelessWidget
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("Riverpod Study")),
body: Center(child: Text("Hello world")),
),
);
}
}
-ConsumerWidget
class MyApp extends ConsumerWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final String value = ref.watch(helloWorldProvider);
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("Riverpod Study")),
body: Center(child: Text(value)),
),
);
}
}
StatefulWidget을 ConsumerStatefulWidget으로 변경
-StatefulWidget
class HomeViewState extends StatefulWidget {
const HomeViewState({Key? key}) : super(key: key);
@override
State<HomeViewState> createState() => _HomeViewStateState();
}
class _HomeViewStateState extends State<HomeViewState> {
@override
Widget build(BuildContext context) {
return Container();
}
}
-ConsumerStatefulWidget 변경
"ref"는 StatefulWidget의 모든 생명주기 상에서 사용할 수 있습니다.
또한 "ref"는 build 메소드 안에서 프로바이더를 구독(listen)하기위해 사용할 수 있습니다.
class HomeView extends ConsumerStatefulWidget {
const HomeView({Key? key}) : super(key: key);
@override
HomeViewState createState() => HomeViewState();
}
class HomeViewState extends ConsumerState<HomeView> {
@override
void initState() {
super.initState();
ref.read(counterProvider);
}
@override
Widget build(BuildContext context) {
final counter = ref.watch(counterProvider);
return Text('$counter');
}
}
ConsumerWidget 과의 차이점은 build 메소드에 ref객체를 전달하지 않습니다.
ConsumerState 객체에 "ref"객체가 포함됩니다.