Riverpod
은 Flutter에서 상태 관리를 보다 안전하고 효율적으로 할 수 있도록 도와주는 패키지로, 기존의 Provider
패키지를 개선하여 다양한 기능과 유연성을 제공합니다. 이를 통해 애플리케이션의 상태를 보다 쉽게 관리하고, 유지보수를 용이하게 합니다.
Provider
의 개선판으로, 상태 관리의 편의성과 안전성을 높여줍니다. 전역 변수로 제공자를 선언하고, ProviderScope
로 감싸 사용합니다.StatelessWidget
과 유사하지만, Riverpod의 상태를 구독할 수 있는 기능을 제공합니다.ref.watch()
: 상태를 구독하고, 상태가 변경될 때마다 빌드합니다.ref.read()
: 상태를 읽기만 하고, 변경 사항을 구독하지 않습니다.NotifierProvider
: 상태 변경을 알리는 Notifier
객체를 제공하는 Provider입니다.StateProvider
: 간단한 상태를 관리하기 위한 Provider입니다.아래 예제는 간단한 카운터 앱을 통해 Riverpod의 사용 방법을 보여줍니다.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
// 상태 제공자 선언
final counterProvider = StateProvider<int>((ref) => 0);
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: CounterApp(),
);
}
}
class CounterApp extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterProvider).state;
return Scaffold(
appBar: AppBar(title: Text('Counter App')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
Text('$counter', style: Theme.of(context).textTheme.headline4),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
ref.read(counterProvider).state++;
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => A()),
ChangeNotifierProvider(create: (context) => B(a: context.read())),
],
child: MyApp(),
);
ProviderScope
로 감싸면 의존성 순서에 상관없이 등록됩니다.final a = StateProvider<int>((ref) => 0);
final b = StateProvider<int>((ref) => ref.watch(a) * 2);
ProviderScope(
child: MyApp(),
);
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => Counter()), // 1
ChangeNotifierProvider(create: (context) => Counter()), // 2
],
child: MyApp(),
);
Counter counter = context.read<Counter>(); // 2번만 접근 가능
final a = NotifierProvider<Counter, int>(() => Counter());
final b = NotifierProvider<Counter, int>(() => Counter());
Counter counter1 = ref.read(a.notifier);
Counter counter2 = ref.read(b.notifier);
BuildContext
를 사용합니다.class MyWidget extends StatelessWidget {
Widget build(BuildContext context) {
Counter counter = context.watch<Counter>();
return Text("${counter.count}");
}
}
WidgetRef
를 별도로 만들어 사용합니다.class MyWidget extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
Counter counter = ref.watch(counterProvider);
return Text("${counter.count}");
}
}
Riverpod에서는 제공자를 전역 변수로 선언합니다. 이는 동일한 클래스를 여러 개 등록하고 사용할 수 있는 유연성을 제공하지만, 전역 변수가 늘어나게 되어 코드 관리가 어려워질 수 있습니다.
Riverpod은 Flutter의 BuildContext
를 사용하지 않고 WidgetRef
를 사용합니다. 이는 Flutter에 의존하지 않는다는 장점이 있지만, ConsumerWidget
과 같은 위젯을 사용하기 위해 추가적인 코드가 필요하게 됩니다.
class MyWidget extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
Counter counter = ref.watch(counterProvider);
return Text("${counter.count}");
}
}
ref.watch
는 필요한 경우에만 호출하여 불필요한 위젯 빌드를 최소화합니다.Riverpod
와 같은 상태 관리 도구를 사용하는 것이 좋습니다.