Flutter 상태 관리 어렵다면? riverpod으로 쉽게 시작하자!
Flutter로 앱을 만들다 보면 꼭 마주하게 되는 문제가 있어요.
바로 "상태 관리(State Management)"예요.
버튼을 눌렀을 때 숫자가 바뀌거나, 로그인한 사용자 정보가 바뀌었을 때
그걸 앱 화면에 반영하려면 상태를 잘 관리해야 하거든요.
이걸 제대로 못하면…
버튼 눌렀는데 값이 안 바뀌고, 다른 화면에서도 이상한 데이터가 보이고…
앱이 고장난 것처럼 보이겠죠? 😰
그래서 오늘은 Flutter에서 상태를 아주 깔끔하게 관리할 수 있게 도와주는
강력한 친구, 바로 riverpod을 소개해드릴게요!
✅ 상태 관리는 왜 필요한 걸까?
- 앱 안에는 버튼 클릭 횟수, 로그인 여부, 장바구니 같은 "상태"들이 있어요.
- 이런 값들은 사용자 행동에 따라 계속 바뀌어요.
- 바뀐 값을 화면에 보여주려면 상태를 추적하고, 변화에 반응하는 구조가 필요해요.
- 앱이 커질수록 상태가 많아지니까 잘 정리된 관리 방식이 꼭 필요하죠!
예를 들어, 쇼핑몰 앱을 만든다고 생각해보세요.
사용자가 상품을 장바구니에 담고, 로그인을 하고, 결제하는 과정마다
앱은 각 상태를 저장하고, 그 상태에 따라 다른 화면을 보여줘야 해요.
이걸 그냥 setState() 하나로 관리하면 나중엔 코드가 엉켜서 손도 못 댈 지경이 되죠.
그래서! 상태를 체계적으로 관리하는 도구가 필요한 거예요.
🧠 riverpod이란?
- Flutter 앱에서 상태를 쉽고 깔끔하게 관리할 수 있게 도와주는 패키지예요.
- 기존 provider 패키지의 단점을 개선해서 나온 최신 도구예요.
- 전역으로 상태를 관리하면서도 타입 안정성, 자동으로 UI 업데이트, 테스트 편리성을 갖추고 있어요.
다른 언어와 비교하자면…
- React에서는 useState, Recoil, Redux
- Vue에서는 Vuex, Pinia
- Android에서는 LiveData, ViewModel
- SwiftUI에서는 @State, @ObservedObject
이런 친구들과 비슷한 역할이에요.
그중에서도 riverpod은 깔끔하고 안전한 사용법으로 Flutter 개발자들 사이에서 인기 폭발 중이에요! 💥
🛠️ riverpod 설치 방법
먼저 패키지를 설치해야겠죠?
항상 설치하는 방법대로, pubspec.yaml에 추가해줄게요.
dependencies:
flutter_riverpod: ^2.6.1
dependencies에 추가했다면, flutter pub get 명령어를 통해서 설치를 완료해주세요.
가장 먼저 작업해야하는 것은 main.dart 파일이에요.
main.dart 파일에서 꼭! ProviderScope로 앱 전체를 감싸줘야 해요.
이걸 잊으면 riverpod이 작동하지 않아요 😅
💡 기본 사용 예제: 카운터 앱
🔧 상태 선언하기
아래처럼 어떤 형의 데이터를 쓸지, 초기값은 뭔지 선언해주면 돼요.
final counterProvider = StateProvider<int>((ref) => 0);
final nameProvider = StateProvider<string>((ref) => 'withMilk');
- StateProvider<int>는 숫자 상태를 다루겠다는 뜻이에요.
- (ref) => 0는 상태의 초기값을 0으로 설정한 거예요.
🖥️ 상태 읽고 변경하기 (전체 코드)
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
// 1. 상태 선언 (0부터 시작하는 카운터)
final counterProvider = StateProvider<int>((ref) => 0);
void main() {
runApp(
// 2. 앱을 ProviderScope로 감싸야 riverpod이 작동함!
ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CounterScreen(),
);
}
}
// 3. 상태를 사용하려면 ConsumerWidget 또는 ConsumerStatefulWidget이 필요함!
class CounterScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// 4. 상태 읽기 - 현재 카운터 값을 가져옴
final count = ref.watch(counterProvider);
return Scaffold(
appBar: AppBar(title: Text('Riverpod 카운터')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('버튼을 누른 횟수:', style: TextStyle(fontSize: 20)),
SizedBox(height: 10),
Text('$count', style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold)),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// 5. 상태 변경 - 기존 값에 1 더하기
ref.read(counterProvider.notifier).state++;
},
child: Text('숫자 증가'),
),
],
),
),
);
}
}
👀 예제 흐름 정리
- counterProvider는 카운터 숫자 상태를 담고 있어요.
- ref.watch(counterProvider)로 현재 숫자를 읽고,
- 버튼을 누르면 ref.read(counterProvider.notifier).state++로 상태를 1 증가시켜요.
- 상태가 바뀌면 riverpod이 자동으로 build() 함수를 다시 실행시켜서, 화면을 최신 값으로 업데이트해줘요!
💡 여기서 꼭 알아야 할 핵심 개념 정리
1. ref란?
- ref는 Provider를 가져오거나, 상태를 조작할 수 있게 해주는 도우미 객체예요.
- ref.watch(), ref.read(), ref.listen() 같은 함수들을 통해 상태에 접근하거나 변경할 수 있어요.
- 마치 "Provider 관리 도구"라고 보면 돼요.
2. 어떤 위젯에서 ref를 쓸 수 있을까?
위젯 종류 | 설명 |
ConsumerWidget | StatelessWidget처럼 생긴 위젯, build 함수에 ref가 들어옴 |
ConsumerStatefulWidget | StatefulWidget에 ref를 사용할 수 있게 도와줌 |
Consumer | 위젯 안의 특정 부분만 상태에 반응하게 만들고 싶을 때 사용 |

👉 예를 들어, 전체 화면이 아니라 특정 버튼이나 텍스트만 상태에 반응하도록 만들고 싶다면 Consumer를 쓰는 게 좋아요!
3. ref로 상태를 가져오는 함수들
함수 | 용도 | 주의사항 |
ref.watch() | Provider의 값을 읽고, 값이 변경되면 자동으로 UI를 다시 그림 | 보통 build() 함수에서 사용 |
ref.read() | Provider의 값을 읽지만, 값이 변경돼도 UI를 다시 그리지 않음 | 이벤트 처리용으로 사용 (onPressed 등) |
ref.listen() | 값이 변경될 때 특정 동작(예: 알림, 에러 처리)을 하고 싶을 때 사용 | UI 렌더링보다는 로직 처리에 사용 |
💬 추가 꿀팁
- watch()는 UI가 변화에 반응해야 할 때 꼭 사용해요. setState를 사용하는 것처럼 값이 바뀔 때 UI가 다시 그려져요!
- read()는 버튼 클릭, 페이지 이동 같은 한 번만 쓰는 이벤트 처리에 사용해요.
- listen()은 알림 메시지, 에러 로그 출력 등 사이드 이펙트(side effect) 발생 시 사용해요.
🌱 다양한 Provider 종류
riverpod에는 다양한 상태 관리 방식이 있어요:
Provider 종류 | 설명 | 예시 |
StateProvider | 숫자, 문자열 등 간단한 상태 관리 | 카운터 |
FutureProvider | 비동기 데이터 (API 요청 등) | 뉴스 목록 불러오기 |
StreamProvider | 실시간 데이터 스트림 관리 | 채팅 메시지 |
NotifierProvider | 더 복잡한 상태/로직 처리 | 로그인 상태, 장바구니 등 |
마지막 정리!
- 앱은 사용자와의 상호작용에 따라 상태가 계속 바뀌는 구조예요.
- 이런 상태를 체계적으로 관리하지 않으면, 앱은 금방 복잡해지고 오류가 생기기 쉬워요.
- riverpod은 Flutter에서 상태를 안정적이고 깔끔하게 관리할 수 있게 도와주는 아주 강력한 도구예요.
- StateProvider는 간단한 숫자나 문자열 같은 상태를 관리할 때 유용하고,
상황에 따라 FutureProvider, StreamProvider, NotifierProvider 등 더 다양한 Provider도 쓸 수 있어요!
마무리 하며...
이번 글에서는 StateProvider를 중심으로 riverpod의 기본 개념과 사용법을 다뤄봤어요.
다음 글에서는 아래와 같은 다양한 Provider의 사용법과 실제 활용 예제를 자세히 소개할 예정이에요:
- FutureProvider로 API 요청하기
- StreamProvider로 실시간 데이터 처리하기
- NotifierProvider로 복잡한 상태와 로직 함께 다루기
Flutter 앱을 한 단계 더 발전시키고 싶은 분들은 꼭 다음 글도 기대해 주세요! 😄