위젯(컴포넌트)이 깊게 중첩되면, 위에서 만든 상태(로그인 정보 등)를 아래 화면까지 계속 손으로 넘겨야 한다(prop drilling). Riverpod은 상태를 전역 상자에 담아두고, 필요한 위젯이 어디서든 직접 꺼내 쓰게 해준다.
final counterProvider = StateProvider<int>((ref) => 0);
React의 Zustand store나 Redux slice를 하나 만드는 것과 같다. 이 상자를 위젯이 구독하면, 값이 바뀔 때 그 위젯만 다시 그려진다.
| 종류 | 용도 | React 비유 |
|---|---|---|
| Provider | 안 바뀌는 값·객체 제공 (서비스, 라우터, 계산값) | useMemo / 의존성 주입 |
| StateProvider | 단순 값 하나 (bool, int, 텍스트) | useState |
| NotifierProvider | 복잡한 상태 + 로직 함께 | Zustand store / reducer |
| FutureProvider | 비동기 결과 (API 호출 등) | React Query |
| StreamProvider | 스트림 구독 | 실시간 구독 |
ref는 "다른 상자에 접근하는 리모컨"이다.
| 방법 | 뜻 | 언제 | React 비유 |
|---|---|---|---|
ref.watch(p) |
구독. 값 바뀌면 다시 build | build 안에서 화면에 값 표시 | useSelector |
ref.read(p) |
1회만 읽음. 구독 X | 버튼 눌렀을 때 등 이벤트 | store.getState() |
ref.listen(p, cb) |
값 바뀔 때 콜백 실행 | 팝업 띄우기 등 부수효과 | useEffect + 구독 |
주의: build() 안에서는
watch, 이벤트 핸들러에서는read. 반대로 쓰면 불필요한 재빌드나 구독 누락이 생긴다.
final myProvider = StateProvider.autoDispose<bool>((ref) => false);
그 상자를 쓰는 화면을 벗어나면 상자를 자동으로 비운다. React 컴포넌트가 언마운트될 때 상태가 사라지는 것과 같다. 페이지 단위 임시 상태(로딩/에러/입력값)에 쓴다.
runApp(ProviderScope(child: App()));
Riverpod이 동작하려면 앱 최상단을 ProviderScope로 감싸야 한다. Redux의 <Provider store={store}>로 앱을 감싸는 것과 같은 역할.
| React | Riverpod |
|---|---|
| useState | StateProvider |
| useReducer / Zustand | NotifierProvider |
| useSelector / 구독 | ref.watch |
| store.getState() | ref.read |
| React Query | FutureProvider |
| <Provider store> | ProviderScope |
관련: "플러터 기초개념" 5번 섹션(Provider와 Riverpod는 왜 쓰나), "routerProvider 패턴" 페이지.