Flutter 개발을 하다 보면 효율적으로 상태를 관리하는 것이 중요합니다.
특히 복잡한 앱을 개발할수록 상태 관리 라이브러리의 선택이 큰 영향을 미치게 됩니다.
이번 포스팅에서는 Riverpod을 단계별로 배우고 간단히 테스트하는 방법을 소개합니다.
1. Riverpod이란?
Riverpod은 Flutter에서 강력하고 유연한 상태 관리 및 의존성 주입 라이브러리입니다. 기존의 Provider의 단점을 보완하여 더 구조적이고 사용하기 쉽게 설계되었습니다.
Riverpod의 주요 특징
• Stateless한 설계: 상태를 외부에서 관리해 위젯이 Stateless로 유지됩니다.
• 명확한 상태 관리: 전역 상태와 지역 상태를 명확히 구분 가능.
• 강력한 테스트 지원: 상태 로직이 분리되어 테스트가 용이.
• 유연성: 단순한 앱부터 복잡한 대규모 앱까지 확장 가능.
2. 프로젝트에 Riverpod 설정하기
Step 1: Riverpod 설치
pubspec.yaml 파일에 Riverpod 의존성을 추가하세요.
dependencies:
flutter_riverpod: ^2.3.6
터미널에서 flutter pub get 명령어로 의존성을 가져옵니다.
Step 2: 기본 설정
모든 Riverpod 상태 관리 기능은 ProviderScope로 감싸야 합니다. main.dart에 다음과 같이 설정합니다.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Riverpod Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const HomePage(),
);
}
}
3. 간단한 Counter 앱 만들어보기
Counter는 상태 관리의 기본 개념을 배우기 좋은 예제입니다. Riverpod으로 상태를 관리하는 방법을 확인해봅시다.
Step 1: 상태를 제공하는 Provider 생성
import 'package:flutter_riverpod/flutter_riverpod.dart';
// 상태를 관리하는 Provider
final counterProvider = StateProvider<int>((ref) => 0);
여기서 StateProvider는 간단한 상태를 관리하는 데 사용됩니다.
1. final:
• counterProvider는 변경되지 않는 상수처럼 선언되어, 재할당이 불가능합니다.
• 즉, 이 Provider의 참조 자체는 고정되어 있으며, 상태는 내부적으로 관리됩니다.
2. counterProvider:
• 상태를 관리하는 Provider의 이름입니다.
• 이 Provider를 통해 UI 위젯에서 상태를 읽거나 업데이트할 수 있습니다.
3. StateProvider<int>:
• Riverpod의 StateProvider는 간단한 상태를 관리하는 데 사용됩니다.
• <int>는 이 Provider가 관리하는 상태의 타입입니다. 여기서는 정수(int)형 상태를 관리합니다.
4. (ref) => 0:
• 초기값 정의:
• ref는 Riverpod이 Provider의 상태를 관리하는 데 필요한 정보를 제공합니다.
• (ref) => 0은 이 Provider의 초기값을 설정합니다. 여기서는 0으로 초기화됩니다.
작동 방식
1. 초기값 제공:
• 앱이 실행되면 counterProvider는 초기값 0을 가지게 됩니다.
2. UI와 상태 연결:
• ref.watch(counterProvider)를 사용해 현재 상태 값을 읽습니다.
• ref.read(counterProvider.notifier).state를 통해 상태를 변경할 수 있습니다.
3. 자동 UI 갱신:
• 상태가 변경되면 counterProvider를 구독하고 있는 모든 위젯이 자동으로 재빌드됩니다.
Step 2: 상태를 UI에 연결
ConsumerWidget을 사용해 상태를 UI와 연결합니다.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class HomePage extends ConsumerWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
// counterProvider의 상태를 읽기
final counter = ref.watch(counterProvider);
return Scaffold(
appBar: AppBar(title: const Text('Riverpod Counter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Counter: $counter', style: const TextStyle(fontSize: 24)),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
// 상태 업데이트
ref.read(counterProvider.notifier).state++;
},
child: const Text('Increment'),
),
],
),
),
);
}
}
4. 비동기 상태 관리
비동기 데이터(예: API 호출, 데이터베이스 쿼리)를 처리하는 경우 FutureProvider를 사용합니다.
Step 1: FutureProvider 생성
// 비동기 데이터를 관리하는 Provider
final futureProvider = FutureProvider<String>((ref) async {
await Future.delayed(const Duration(seconds: 2));
return 'Loaded Data!';
});
Step 2: UI에 비동기 상태 표시
ref.watch()로 상태를 구독하고 데이터를 표시합니다.
class AsyncPage extends ConsumerWidget {
const AsyncPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final asyncValue = ref.watch(futureProvider);
return Scaffold(
appBar: AppBar(title: const Text('Async Example')),
body: Center(
child: asyncValue.when(
data: (data) => Text(data),
loading: () => const CircularProgressIndicator(),
error: (error, stack) => Text('Error: $error'),
),
),
);
}
}
5. 복잡한 상태 관리
앱이 점점 커지면서 상태 관리 로직도 복잡해질 수 있습니다. 이런 경우에는 StateNotifier를 사용하여 상태를 더 체계적으로 관리합니다.
Step 1: StateNotifier 정의
import 'package:flutter_riverpod/flutter_riverpod.dart';
// 상태 로직을 관리하는 클래스
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
void decrement() => state--;
}
// StateNotifierProvider 생성
final counterNotifierProvider =
StateNotifierProvider<CounterNotifier, int>((ref) => CounterNotifier());
Step 2: UI와 연결
class NotifierPage extends ConsumerWidget {
const NotifierPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterNotifierProvider);
return Scaffold(
appBar: AppBar(title: const Text('Notifier Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Counter: $counter', style: const TextStyle(fontSize: 24)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: const Icon(Icons.remove),
onPressed: () =>
ref.read(counterNotifierProvider.notifier).decrement(),
),
IconButton(
icon: const Icon(Icons.add),
onPressed: () =>
ref.read(counterNotifierProvider.notifier).increment(),
),
],
),
],
),
),
);
}
}
6. 학습을 확장하기 위한 팁
1. 작은 기능부터 테스트:
• 리스트 관리, 캘린더 업데이트와 같은 작은 기능부터 시작하세요.
2. 공식 문서 학습:
• Riverpod 공식 문서(https://riverpod.dev/)를 참고하여 다양한 예제를 실습.
3. 테스트 작성:
• Riverpod은 상태를 외부에서 관리하기 때문에 상태 로직 테스트가 쉽습니다.
마무리
이제 Riverpod의 기본 개념과 사용법을 익히셨습니다!
간단한 앱부터 복잡한 앱까지 Riverpod을 사용해 효과적으로 상태를 관리해 보세요. 😊
'IT > flutter' 카테고리의 다른 글
[상태관리] Riverpod - FutureProvider 비동기 데이터 관리 (0) | 2024.12.19 |
---|---|
[상태관리]Riverpod의 WidgetRef 객체 (0) | 2024.12.19 |
[flutter] 플러터 ReorderableListView 사용법 (0) | 2024.01.23 |
[flutter]플러터 리스트뷰 ListView 사용법 (2) | 2024.01.22 |
[flutter]플러터 스크롤뷰 SingleChildScrollView 사용법 (0) | 2024.01.22 |