Riverpod는 Flutter에서 상태 관리를 위해 사용되는 라이브러리로, 코드의 유연성, 테스트 가능성, 그리고 확장성을 제공하는 방식으로 설계되었습니다. Riverpod는 기존의 Provider 패키지에서 발전한 것으로, 더 많은 기능과 강력한 제어를 제공합니다.
Riverpod의 주요 특징
컴파일 타임 안전성: Riverpod는 컴파일 타임에 오류를 잡아낼 수 있습니다. 잘못된 상태 관리 코드를 작성했을 때 컴파일러에서 바로 오류를 알려줍니다.
전역 상태 관리: Riverpod는 애플리케이션의 상태를 전역적으로 관리하는 데 유용합니다. Provider를 사용해 다양한 상태를 중앙에서 관리하고, 필요한 곳에서 쉽게 접근할 수 있습니다.
디펜던시 주입: 상태를 공유하는 다른 객체나 데이터 의존성을 쉽게 주입할 수 있어, 코드의 모듈화와 재사용성을 높입니다.
변경 불가능한 상태: 상태를 변경할 때 Provider의 상태를 새로 만들거나 변경하는 방식으로, 기존 상태를 직접 변경하지 않고 불변성을 유지합니다. 이는 상태 변화 추적 및 디버깅에 유리합니다.
Riverpod의 주요 개념
Provider: 상태를 제공하는 기본적인 구성 요소입니다. Provider는 값을 제공하거나, 값을 계산하고, 그 값을 소비하는데 사용됩니다. 예를 들어, API 요청 후 데이터를 받아오는 데 사용할 수 있습니다.
Consumer: Consumer는 Provider로부터 값을 소비하는 위젯입니다. 이 위젯은 해당 Provider가 변경될 때마다 리빌드됩니다.
StateNotifierProvider: StateNotifier는 상태를 변경하는 클래스로, 상태를 더 세밀하게 관리할 수 있습니다. 이와 연결된 StateNotifierProvider를 사용해 상태를 관리하고, 상태 변경을 StateNotifier를 통해 수행합니다.
Scoped Providers: Provider는 기본적으로 애플리케이션 전체에서 접근할 수 있지만, 특정 범위 내에서만 값을 제공하려면 Scoped Provider를 사용할 수 있습니다.
사용 예시
1. Provider 사용 예시
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/material.dart';
// 상태를 관리하는 provider
final counterProvider = Provider((ref) => 0);
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterProvider); // 상태를 가져옵니다.
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Riverpod Example')),
body: Center(child: Text('Counter: $counter')),
),
);
}
}
2. StateNotifier 사용 예시
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/material.dart';
// 상태 변경 클래스를 정의
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
void decrement() => state--;
}
// 상태를 관리하는 provider
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterProvider); // 상태를 가져옵니다.
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Riverpod Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Counter: $counter'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(Icons.add),
onPressed: () {
ref.read(counterProvider.notifier).increment(); // 상태를 변경
},
),
IconButton(
icon: Icon(Icons.remove),
onPressed: () {
ref.read(counterProvider.notifier).decrement(); // 상태를 변경
},
),
],
),
],
),
),
),
);
}
}
Riverpod의 장점
테스트 용이성: 상태를 분리하여 테스트할 수 있기 때문에, UI와 비즈니스 로직을 명확하게 구분하고, 테스트를 쉽게 작성할 수 있습니다.
코드 재사용성: Provider를 사용하면 상태를 여러 위젯에서 쉽게 공유하고 재사용할 수 있습니다.
자동 의존성 관리: Provider는 필요한 데이터를 자동으로 관리해주며, 의존성 관계를 쉽게 설정할 수 있습니다.
Riverpod는 상태 관리뿐만 아니라 비즈니스 로직의 분리와 테스트의 용이성, 그리고 코드의 유지보수성을 높이는 데 큰 장점이 있습니다.