Riverpod 오픈소스 완전 분석

Flutter 상태 관리의 정석 Riverpod! 기본 사용법부터 내부 아키텍처까지 소스 코드를 직접 읽으며 완벽하게 이해합니다. Provider, Notifier, AsyncValue 등 핵심 API를 마스터하고 실전 프로젝트에 적용해봅니다. GitHub: https://github.com/rrousselGit/riverpod

Flutter,State Management,Dart중급
28시간
19개 항목
학습 진행률0 / 19 (0%)

학습 항목

1. Flutter,State Management
초급
Riverpod 소개 및 설치 완벽 가이드
퀴즈튜토리얼
2. Flutter,State Management
초급
Provider 기본 개념 완벽 가이드
퀴즈튜토리얼
3. Flutter,State Management
초급
ref.watch와 ref.read 완벽 이해
퀴즈튜토리얼
4. Flutter,State Management
초급
ConsumerWidget과 Consumer 사용법 완벽 가이드
퀴즈튜토리얼
5. Flutter,State Management
초급
FutureProvider로 비동기 데이터 처리 완벽 가이드
퀴즈튜토리얼
6. Flutter,State Management
초급
AsyncValue로 로딩/에러/데이터 상태 관리 완벽 가이드
퀴즈튜토리얼
7. Flutter,State Management
초급
StreamProvider로 실시간 데이터 처리 완벽 가이드
퀴즈
8. Flutter,State Management
초급
Notifier와 NotifierProvider 완벽 가이드
퀴즈튜토리얼
9. Flutter,State Management
초급
AsyncNotifier로 비동기 상태 관리 완벽 가이드
퀴즈튜토리얼
10. Flutter,State Management
초급
Riverpod 코드 제너레이션 완벽 가이드
퀴즈튜토리얼
11. Flutter,State Management
초급
ProviderScope와 오버라이드 완벽 가이드
퀴즈튜토리얼
12. Flutter,State Management
초급
Provider 간 의존성 관리 완벽 가이드
퀴즈튜토리얼
13. Flutter,State Management
초급
Riverpod 테스팅 전략 완벽 가이드
퀴즈튜토리얼
14. Flutter,State Management
초급
Riverpod 내부 아키텍처 분석
퀴즈튜토리얼
15. Flutter,State Management
초급
실전 프로젝트 Todo 앱 만들기 완벽 가이드
퀴즈튜토리얼
16. Flutter,State Management
초급
Riverpod 3.0 Mutation으로 폼 제출 처리 완벽 가이드
퀴즈튜토리얼
17. Flutter,State Management
초급
Riverpod 3.0 Offline Persistence 완벽 가이드
퀴즈튜토리얼
18. Flutter,State Management
초급
AsyncValue.requireValue로 Provider 결합하기
퀴즈튜토리얼
19. Flutter,State Management
초급
Riverpod 3.0 Retry와 에러 복구 전략 완벽 가이드
퀴즈튜토리얼
1 / 19
🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

이미지 로딩 중...

Riverpod 소개 및 설치 완벽 가이드 - 슬라이드 1/7
상세 보기

Riverpod 소개 및 설치 완벽 가이드

Flutter 상태 관리의 새로운 표준인 Riverpod을 처음 접하는 개발자를 위한 가이드입니다. Provider와의 차이점부터 실제 프로젝트 설치, 첫 번째 Provider 만들기까지 단계별로 알아봅니다.


목차

  1. Riverpod이란_무엇인가
  2. Provider와의_차이점
  3. 패키지_종류_선택하기
  4. 프로젝트에_설치하기
  5. ProviderScope_설정
  6. 첫_번째_Provider_만들기

1. Riverpod이란 무엇인가

김개발 씨는 Flutter 프로젝트를 진행하면서 상태 관리의 벽에 부딪혔습니다. 여러 화면에서 같은 데이터를 공유해야 하는데, setState만으로는 도저히 감당이 되지 않았습니다.

선배에게 물어보니 "Riverpod 한번 써봐"라는 답이 돌아왔습니다.

Riverpod은 Flutter에서 가장 현대적인 상태 관리 솔루션입니다. 마치 중앙 관제탑처럼 앱 전체의 데이터 흐름을 체계적으로 관리해줍니다.

컴파일 타임에 오류를 잡아주고, 테스트하기 쉬운 구조를 제공한다는 점에서 많은 개발자들의 사랑을 받고 있습니다.

다음 코드를 살펴봅시다.

// Riverpod의 기본 구조를 살펴봅니다
import 'package:flutter_riverpod/flutter_riverpod.dart';

// Provider 선언 - 전역에서 접근 가능한 상태 정의
final counterProvider = StateProvider<int>((ref) {
  return 0; // 초기값 설정
});

// 위젯에서 상태 읽기
class MyWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // ref.watch로 상태 구독 - 변경시 자동 리빌드
    final count = ref.watch(counterProvider);
    return Text('Count: $count');
  }
}

김개발 씨는 입사 6개월 차 Flutter 개발자입니다. 최근 맡은 프로젝트는 쇼핑몰 앱인데, 장바구니 정보를 여러 화면에서 공유해야 하는 상황이었습니다.

처음에는 setState와 콜백 함수로 해결하려 했지만, 코드가 점점 스파게티처럼 엉켜갔습니다. "이렇게 하면 유지보수가 너무 힘들어요." 팀장님이 코드 리뷰를 하며 말했습니다.

"상태 관리 라이브러리를 도입해야 할 것 같은데, Riverpod이 요즘 대세더라고요." 그렇다면 Riverpod이란 정확히 무엇일까요? 쉽게 비유하자면, Riverpod은 마치 아파트 단지의 중앙 관리 사무소와 같습니다.

각 세대에서 필요한 정보를 관리사무소에 요청하면, 관리사무소가 정확한 정보를 전달해줍니다. 한 세대에서 변경 사항이 생기면 관련된 모든 세대에 자동으로 알림이 갑니다.

Riverpod도 마찬가지로 앱 전체의 상태를 중앙에서 관리하고, 필요한 위젯에게 정확히 전달합니다. Riverpod이 등장하기 전에는 어떤 문제가 있었을까요?

가장 큰 문제는 prop drilling이었습니다. 최상위 위젯에서 최하위 위젯까지 데이터를 전달하려면, 중간에 있는 모든 위젯이 그 데이터를 받아서 다시 전달해야 했습니다.

10단계를 거쳐야 한다면 10번의 전달 코드를 작성해야 했던 것입니다. 또 다른 문제는 상태 변경 시 어떤 위젯이 다시 그려져야 하는지 정확히 제어하기 어려웠다는 점입니다.

불필요한 리빌드가 발생하면 앱 성능이 저하됩니다. 사용자 경험에 직접적인 영향을 미치는 심각한 문제였습니다.

바로 이런 문제들을 해결하기 위해 Riverpod이 탄생했습니다. Riverpod의 창시자인 Remi Rousselet은 기존 Provider 패키지의 한계를 극복하고자 했습니다.

그 결과물이 바로 Riverpod입니다. 이름을 자세히 보면 Provider의 철자를 재배열한 것임을 알 수 있습니다.

완전히 새로운 설계 철학을 담았지만, 친숙함을 유지하고자 한 것이죠. Riverpod의 가장 큰 장점은 컴파일 타임 안전성입니다.

기존 Provider에서는 런타임에야 발견되던 오류들을 Riverpod에서는 코드를 작성하는 순간 잡아낼 수 있습니다. 빨간 줄이 뜨면 즉시 수정하면 됩니다.

위의 코드를 살펴보면, counterProvider라는 전역 변수를 선언했습니다. StateProvider는 단순한 값을 관리할 때 사용합니다.

ref 파라미터는 다른 Provider에 접근할 수 있게 해주는 열쇠입니다. ConsumerWidget과 ref.watch를 통해 상태 변화를 구독하면, 값이 바뀔 때마다 위젯이 자동으로 다시 그려집니다.

실무에서는 사용자 인증 상태, 장바구니 목록, 테마 설정 등 앱 전반에서 공유되어야 하는 데이터를 Riverpod으로 관리합니다. 한 화면에서 로그아웃하면 다른 모든 화면에서도 자동으로 로그인 상태가 해제되는 것이 바로 이 원리입니다.

김개발 씨는 Riverpod의 개념을 이해하고 나서 고개를 끄덕였습니다. "중앙에서 상태를 관리하고, 필요한 곳에 자동으로 전달해주는 거군요!"

실전 팁

💡 - Riverpod은 Provider의 철자를 재배열한 이름으로, Provider의 진화된 버전입니다

  • 컴파일 타임 안전성 덕분에 런타임 오류를 크게 줄일 수 있습니다
  • 공식 문서(riverpod.dev)에서 최신 정보를 확인하세요

2. Provider와의 차이점

김개발 씨는 인터넷을 검색하다가 혼란에 빠졌습니다. "Provider랑 Riverpod이 뭐가 다른 거지?

둘 다 상태 관리 아닌가?" 블로그마다 설명이 조금씩 달라서 머리가 복잡해졌습니다. 마침 옆자리 박시니어 씨가 커피를 마시러 가면서 물었습니다.

"뭐 때문에 고민이야?"

Provider는 BuildContext에 의존하는 반면, Riverpod은 BuildContext 없이도 어디서든 상태에 접근할 수 있습니다. 이 차이가 테스트 용이성과 코드 구조에 큰 영향을 미칩니다.

Riverpod은 같은 타입의 Provider를 여러 개 만들 수 있고, 컴파일 타임에 오류를 잡아줍니다.

다음 코드를 살펴봅시다.

// Provider 방식 - BuildContext 필요
final value = Provider.of<MyState>(context);
// 또는
final value = context.watch<MyState>();

// Riverpod 방식 - BuildContext 불필요
final myStateProvider = StateProvider<MyState>((ref) => MyState());

// 어디서든 접근 가능
class MyNotifier {
  final Ref ref;
  MyNotifier(this.ref);

  void doSomething() {
    // BuildContext 없이도 상태 접근 가능
    final state = ref.read(myStateProvider);
  }
}

박시니어 씨는 김개발 씨의 모니터를 잠시 들여다보더니 의자를 끌어왔습니다. "이거 헷갈리는 사람 많아.

내가 설명해줄게." Provider는 Flutter 생태계에서 오랫동안 사랑받아온 상태 관리 솔루션입니다. 구글에서도 공식적으로 추천했을 정도로 검증된 라이브러리입니다.

하지만 사용하다 보면 몇 가지 불편한 점들이 있었습니다. 가장 큰 차이는 BuildContext 의존성입니다.

마치 도서관에서 책을 빌리려면 반드시 도서관 건물 안에 있어야 하는 것과 같습니다. Provider를 사용하려면 반드시 위젯 트리 안에서, 즉 BuildContext가 있는 곳에서만 접근할 수 있습니다.

그런데 비즈니스 로직을 위젯과 분리하고 싶다면 어떨까요? Riverpod은 이 문제를 해결했습니다.

마치 모바일 도서관 앱처럼 어디서든 책 목록을 확인하고 예약할 수 있게 된 것입니다. BuildContext가 없는 순수 Dart 클래스에서도 상태에 접근할 수 있습니다.

이것은 테스트 코드 작성을 획기적으로 쉽게 만들어줍니다. 두 번째 차이는 동일 타입 Provider 문제입니다.

Provider에서는 같은 타입의 Provider를 여러 개 만들기가 까다롭습니다. 예를 들어 '읽은 책 목록'과 '읽고 싶은 책 목록'이 둘 다 List<Book> 타입이라면, Provider에서는 이를 구분하기 위해 추가 작업이 필요합니다.

Riverpod에서는 간단히 다른 이름의 Provider를 선언하면 됩니다. 세 번째는 컴파일 타임 안전성입니다.

Provider에서 존재하지 않는 Provider를 읽으려고 하면 앱이 실행되고 나서야 오류가 발생합니다. 사용자가 특정 화면에 들어갔을 때 갑자기 앱이 죽는 상황이 발생할 수 있습니다.

Riverpod에서는 이런 오류가 코드 작성 단계에서 바로 발견됩니다. 네 번째 차이는 Provider 조합의 용이성입니다.

Riverpod에서는 ref 객체를 통해 다른 Provider를 쉽게 참조할 수 있습니다. 하나의 Provider가 다른 Provider의 값을 읽고, 그 값이 바뀌면 자동으로 업데이트됩니다.

마치 엑셀에서 셀 참조를 하면 원본 셀이 바뀔 때 참조한 셀도 자동으로 바뀌는 것과 같습니다. 박시니어 씨가 정리해주었습니다.

"결국 Riverpod은 Provider의 단점들을 보완해서 새로 만든 거야. 새 프로젝트라면 Riverpod을 쓰는 게 좋고, 기존 Provider 프로젝트도 점진적으로 마이그레이션하는 추세야." 김개발 씨가 물었습니다.

"그럼 Provider는 이제 안 쓰는 건가요?" "기존 프로젝트에서는 여전히 많이 쓰여. 하지만 Riverpod의 창시자가 Provider도 만든 사람이고, 본인도 Riverpod을 더 권장하고 있어."

실전 팁

💡 - 새 프로젝트는 Riverpod으로 시작하는 것을 권장합니다

  • Provider에서 Riverpod으로 마이그레이션 가이드가 공식 문서에 있습니다
  • 두 라이브러리의 창시자가 동일인물(Remi Rousselet)입니다

3. 패키지 종류 선택하기

김개발 씨가 pub.dev에서 riverpod을 검색하니 세 가지 패키지가 나왔습니다. riverpod, flutter_riverpod, hooks_riverpod.

"이게 다 뭐지? 어떤 걸 설치해야 하는 거야?" 패키지 설명을 읽어봐도 영어라 헷갈렸습니다.

riverpod은 순수 Dart용, flutter_riverpod은 Flutter 프로젝트용, hooks_riverpod은 flutter_hooks와 함께 사용할 때 선택합니다. 일반적인 Flutter 프로젝트라면 flutter_riverpod을 설치하면 됩니다.

hooks를 사용하고 있다면 hooks_riverpod을 선택하세요.

다음 코드를 살펴봅시다.

// pubspec.yaml 설정 예시

// 1. 순수 Dart 프로젝트 (Flutter 없이)
dependencies:
  riverpod: ^2.5.1

// 2. 일반 Flutter 프로젝트 (가장 흔한 선택)
dependencies:
  flutter_riverpod: ^2.5.1

// 3. flutter_hooks를 사용하는 Flutter 프로젝트
dependencies:
  hooks_riverpod: ^2.5.1
  flutter_hooks: ^0.20.5

박시니어 씨가 김개발 씨 옆으로 다가왔습니다. "패키지 선택 때문에 고민이구나.

이거 처음 보면 다 헷갈려." Riverpod 생태계에는 세 가지 패키지가 존재합니다. 각각의 용도가 다르기 때문에 프로젝트 상황에 맞게 선택해야 합니다.

첫 번째, riverpod 패키지입니다. 이것은 순수 Dart용 패키지입니다.

Flutter 없이 Dart만으로 서버 사이드 애플리케이션을 만들거나, 커맨드라인 도구를 개발할 때 사용합니다. 일반적인 모바일 앱 개발자라면 이 패키지를 직접 설치할 일은 거의 없습니다.

두 번째, flutter_riverpod 패키지입니다. 대부분의 Flutter 개발자가 선택하는 패키지입니다.

Flutter 프로젝트에 필요한 모든 기능이 포함되어 있습니다. ConsumerWidget, ConsumerStatefulWidget 같은 Flutter 전용 위젯들을 제공합니다.

특별한 이유가 없다면 이 패키지를 선택하면 됩니다. 세 번째, hooks_riverpod 패키지입니다.

flutter_hooks 라이브러리를 이미 사용하고 있는 프로젝트를 위한 패키지입니다. React의 Hooks에서 영감을 받은 flutter_hooks는 위젯의 생명주기 관리를 더 간결하게 해줍니다.

hooks_riverpod은 이 두 라이브러리를 매끄럽게 연결해줍니다. 마치 자동차를 구매할 때와 비슷합니다.

riverpod은 엔진만 있는 상태이고, flutter_riverpod은 일반 승용차, hooks_riverpod은 스포츠 패키지가 추가된 차량과 같습니다. 기본 주행에는 일반 승용차로 충분하지만, 특별한 기능이 필요하다면 패키지를 추가하는 것입니다.

김개발 씨가 물었습니다. "저희 프로젝트는 flutter_hooks를 안 쓰는데, 나중에 쓸 수도 있으면 hooks_riverpod을 설치하는 게 좋을까요?" 박시니어 씨가 고개를 저었습니다.

"지금 필요한 것만 설치해. flutter_riverpod으로 시작하고, 나중에 hooks가 필요하면 그때 바꾸면 돼.

마이그레이션이 어렵지 않아." 중요한 점은 세 패키지 모두 핵심 기능은 동일하다는 것입니다. Provider 선언 방식, ref 사용법, 상태 관리 패턴 모두 같습니다.

차이는 Flutter 통합 부분과 추가 유틸리티뿐입니다. 버전 선택도 중요합니다.

2024년 기준으로 Riverpod 2.x 버전이 안정화되어 있습니다. 새 프로젝트라면 최신 2.x 버전을 사용하세요.

1.x에서 2.x로 넘어오면서 많은 개선이 이루어졌습니다.

실전 팁

💡 - 처음 시작한다면 flutter_riverpod을 선택하세요

  • hooks_riverpod은 flutter_hooks 경험이 있을 때 고려하세요
  • 세 패키지 모두 핵심 API는 동일합니다

4. 프로젝트에 설치하기

이제 실제로 프로젝트에 Riverpod을 설치할 시간입니다. 김개발 씨는 터미널을 열고 명령어를 입력할 준비를 했습니다.

"명령어 한 줄이면 되겠지?" 생각보다 간단한 과정에 김개발 씨는 안도의 한숨을 쉬었습니다.

Riverpod 설치는 pub.dev에서 패키지를 추가하는 일반적인 방식과 동일합니다. flutter pub add 명령어로 간편하게 설치하거나, pubspec.yaml에 직접 추가할 수 있습니다.

코드 생성 기능을 활용하려면 riverpod_annotation과 riverpod_generator도 함께 설치합니다.

다음 코드를 살펴봅시다.

// 터미널에서 설치하는 방법
flutter pub add flutter_riverpod

// 코드 생성 기능을 사용하려면 추가 패키지 필요
flutter pub add riverpod_annotation
flutter pub add dev:riverpod_generator
flutter pub add dev:build_runner

// pubspec.yaml 직접 수정 시
dependencies:
  flutter:
    sdk: flutter
  flutter_riverpod: ^2.5.1
  riverpod_annotation: ^2.3.5

dev_dependencies:
  riverpod_generator: ^2.4.0
  build_runner: ^2.4.9

김개발 씨는 새 Flutter 프로젝트를 생성하고 터미널을 열었습니다. 설치 과정은 생각보다 간단했습니다.

기본 설치는 한 줄이면 충분합니다. 터미널에 flutter pub add flutter_riverpod을 입력하면 끝입니다.

pub.dev에서 최신 버전을 자동으로 찾아서 pubspec.yaml에 추가해줍니다. 이후 자동으로 flutter pub get이 실행되어 패키지가 다운로드됩니다.

하지만 박시니어 씨가 덧붙였습니다. "요즘은 코드 생성 기능을 같이 쓰는 추세야.

보일러플레이트 코드를 많이 줄여주거든." 코드 생성(Code Generation) 기능은 Riverpod 2.0부터 도입된 강력한 기능입니다. @riverpod 어노테이션을 붙이면 Provider 코드를 자동으로 생성해줍니다.

타이핑 실수를 줄이고 일관된 코드 스타일을 유지할 수 있습니다. 코드 생성을 사용하려면 추가 패키지가 필요합니다.

riverpod_annotation은 어노테이션을 제공하고, riverpod_generator는 실제 코드를 생성합니다. build_runner는 Dart 생태계의 표준 코드 생성 도구입니다.

설치 후에는 반드시 패키지가 제대로 설치되었는지 확인하세요. pubspec.yaml 파일을 열어 dependencies 섹션에 flutter_riverpod이 추가되었는지 봅니다.

빨간 줄이 뜨거나 임포트가 안 된다면 flutter pub get을 다시 실행해보세요. 김개발 씨가 질문했습니다.

"코드 생성은 꼭 써야 하나요?" "필수는 아니야. 처음 배울 때는 수동으로 Provider를 작성하면서 구조를 이해하는 게 좋아.

익숙해지면 코드 생성으로 넘어가도 돼." 버전 충돌이 발생할 수도 있습니다. 다른 패키지와 의존성이 겹치면 flutter pub get에서 오류가 날 수 있습니다.

이럴 때는 버전 범위를 조정하거나, flutter pub upgrade를 시도해보세요. IDE 설정도 확인하면 좋습니다.

VS Code라면 Dart와 Flutter 확장이 설치되어 있어야 자동완성이 제대로 작동합니다. Android Studio도 마찬가지로 Flutter 플러그인이 필요합니다.

실전 팁

💡 - flutter pub add는 최신 호환 버전을 자동으로 찾아줍니다

  • 코드 생성 기능은 선택사항이지만 대규모 프로젝트에서 유용합니다
  • 설치 후 IDE를 재시작하면 자동완성이 더 잘 작동합니다

5. ProviderScope 설정

패키지 설치를 마친 김개발 씨가 바로 Provider를 사용하려 했습니다. 그런데 앱을 실행하니 오류가 발생했습니다.

"ProviderScope가 없습니다"라는 메시지를 보고 당황했습니다. Provider를 선언했는데 왜 또 다른 설정이 필요한 걸까요?

ProviderScope는 Riverpod이 작동하기 위한 필수 설정입니다. 앱의 최상위에서 모든 Provider의 상태를 보관하는 컨테이너 역할을 합니다.

main.dart의 runApp에서 앱 전체를 ProviderScope로 감싸야 합니다. 이 설정 없이는 어떤 Provider도 사용할 수 없습니다.

다음 코드를 살펴봅시다.

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  // ProviderScope로 앱 전체를 감싸기
  runApp(
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Riverpod Demo',
      home: HomeScreen(),
    );
  }
}

김개발 씨는 빨간 오류 메시지를 보며 멈칫했습니다. "분명히 설치는 다 했는데..." 박시니어 씨가 화면을 보더니 웃었습니다.

"ProviderScope를 빼먹었구나. 이거 필수야." ProviderScope는 마치 회사의 서버실과 같습니다.

회사의 모든 데이터가 서버실의 서버에 저장되듯이, 앱의 모든 Provider 상태가 ProviderScope 안에 저장됩니다. 서버실 없이 회사가 운영될 수 없듯이, ProviderScope 없이는 Riverpod이 작동하지 않습니다.

설정 방법은 간단합니다. main.dart 파일에서 runApp 함수 안의 앱 위젯을 ProviderScope로 감싸면 됩니다.

단 세 줄만 추가하면 됩니다. 왜 이런 설정이 필요할까요?

Riverpod은 Provider의 상태를 어딘가에 저장해야 합니다. ProviderScope가 바로 그 저장소입니다.

전역 변수처럼 보이는 Provider 선언문은 사실 "이런 상태를 만들겠다"는 설계도일 뿐입니다. 실제 상태 값은 ProviderScope 안에서 관리됩니다.

이 구조 덕분에 테스트가 쉬워집니다. 테스트마다 새로운 ProviderScope를 만들면 깨끗한 상태에서 시작할 수 있습니다.

테스트 간에 상태가 오염되는 문제를 방지할 수 있습니다. 김개발 씨가 물었습니다.

"그럼 ProviderScope를 여러 개 쓸 수도 있나요?" "좋은 질문이야. 가능해.

특정 화면에서만 사용하는 Provider를 격리하고 싶을 때 중첩 ProviderScope를 쓸 수 있어. 하지만 처음에는 루트에 하나만 두는 걸 권장해." 주의할 점이 있습니다.

ProviderScope는 반드시 앱의 최상위에 위치해야 합니다. MaterialApp이나 CupertinoApp보다 위에 있어야 합니다.

순서가 바뀌면 일부 Provider가 제대로 작동하지 않을 수 있습니다. ProviderScope에는 overrides 파라미터도 있습니다.

테스트할 때 특정 Provider의 값을 다른 것으로 교체할 수 있습니다. 예를 들어 실제 API 대신 가짜 데이터를 반환하도록 설정할 수 있습니다.

김개발 씨가 ProviderScope를 추가하고 앱을 다시 실행하니 오류가 사라졌습니다. "이제 진짜 시작이네요!"

실전 팁

💡 - ProviderScope는 반드시 앱의 최상위에 배치하세요

  • 테스트에서는 각 테스트마다 새 ProviderScope를 생성합니다
  • overrides 파라미터로 Provider 값을 테스트용으로 교체할 수 있습니다

6. 첫 번째 Provider 만들기

드디어 준비가 끝났습니다. 김개발 씨는 설레는 마음으로 첫 번째 Provider를 만들 준비를 했습니다.

"카운터 앱부터 시작해볼까?" 간단한 예제로 시작해서 점점 복잡한 기능으로 나아가는 것이 학습의 정석입니다.

가장 기본적인 StateProvider를 만들어봅니다. StateProvider는 단순한 값을 저장하고 변경할 때 사용합니다.

전역 변수로 Provider를 선언하고, ConsumerWidget에서 ref.watch로 값을 읽고, ref.read로 값을 변경합니다.

다음 코드를 살펴봅시다.

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

// 1. Provider 선언 - 전역 변수로 정의
final counterProvider = StateProvider<int>((ref) {
  return 0; // 초기값
});

// 2. ConsumerWidget으로 상태 사용
class CounterScreen extends ConsumerWidget {
  const CounterScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 3. ref.watch로 상태 구독
    final count = ref.watch(counterProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('Counter')),
      body: Center(
        child: Text('Count: $count', style: const TextStyle(fontSize: 48)),
      ),
      floatingActionButton: FloatingActionButton(
        // 4. ref.read로 상태 변경
        onPressed: () => ref.read(counterProvider.notifier).state++,
        child: const Icon(Icons.add),
      ),
    );
  }
}

김개발 씨가 코드를 작성하기 시작했습니다. 박시니어 씨가 옆에서 지켜보며 설명을 덧붙였습니다.

첫 번째 단계는 Provider 선언입니다. 파일 최상단에 전역 변수로 Provider를 선언합니다.

final counterProvider = StateProvider<int>((ref) => 0); 이 한 줄이 "정수형 상태를 관리하겠다, 초기값은 0이다"라고 선언하는 것입니다. 마치 창고에 "여기에 숫자를 보관합니다"라고 라벨을 붙이는 것과 같습니다.

StateProvider는 가장 단순한 형태의 Provider입니다. 숫자, 문자열, 불리언 같은 간단한 값을 저장할 때 사용합니다.

더 복잡한 상태는 다른 종류의 Provider를 사용합니다. 두 번째 단계는 ConsumerWidget 사용입니다.

일반적인 StatelessWidget 대신 ConsumerWidget을 상속합니다. build 메서드에 WidgetRef ref 파라미터가 추가됩니다.

이 ref가 바로 Provider 세계로 통하는 열쇠입니다. "왜 StatelessWidget을 안 쓰나요?"라고 김개발 씨가 물었습니다.

"StatelessWidget은 Provider를 읽을 방법이 없어. ConsumerWidget은 ref를 제공해주거든.

StatefulWidget을 쓰고 싶으면 ConsumerStatefulWidget을 쓰면 돼." 세 번째 단계는 ref.watch로 상태 읽기입니다. ref.watch(counterProvider)를 호출하면 현재 카운터 값을 가져옵니다.

중요한 점은 이 값이 바뀌면 위젯이 자동으로 다시 빌드된다는 것입니다. "구독"한다고 표현합니다.

유튜브 채널을 구독하면 새 영상이 올라올 때 알림을 받는 것처럼요. 네 번째 단계는 ref.read로 상태 변경입니다.

버튼을 누르면 ref.read(counterProvider.notifier).state++가 실행됩니다. 여기서 notifier는 상태를 변경할 수 있는 객체입니다.

state에 직접 접근해서 값을 증가시킵니다. "watch랑 read가 뭐가 달라요?" "watch는 값이 바뀔 때마다 리빌드되게 구독하는 거고, read는 그 순간의 값만 딱 한 번 읽는 거야.

버튼 onPressed처럼 일회성 동작에서는 read를 써." 이 패턴을 이해하면 Riverpod의 80%를 이해한 것입니다. Provider 선언, ConsumerWidget, ref.watch, ref.read.

이 네 가지가 핵심입니다. 나머지는 이 기본 패턴의 응용입니다.

김개발 씨가 앱을 실행하고 버튼을 눌러봤습니다. 숫자가 올라갑니다.

"와, 생각보다 간단하네요!" 박시니어 씨가 웃었습니다. "기본은 간단해.

하지만 이걸 바탕으로 복잡한 앱도 만들 수 있어. 비동기 처리, 상태 조합, 의존성 주입까지.

천천히 하나씩 배워나가면 돼."

실전 팁

💡 - ref.watch는 build 메서드 안에서, ref.read는 콜백 함수 안에서 사용하세요

  • StateProvider는 단순한 값에만 사용하고, 복잡한 로직은 NotifierProvider를 고려하세요
  • Provider 이름은 명확하게 지어야 나중에 찾기 쉽습니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Flutter#Riverpod#StateManagement#Provider#ProviderScope#Flutter,State Management