왜 필요한가

위젯(컴포넌트)이 깊게 중첩되면, 위에서 만든 상태(로그인 정보 등)를 아래 화면까지 계속 손으로 넘겨야 한다(prop drilling). Riverpod은 상태를 전역 상자에 담아두고, 필요한 위젯이 어디서든 직접 꺼내 쓰게 해준다.

핵심 개념: Provider = "상태를 담아 어디서든 꺼내 쓰는 상자"

final counterProvider = StateProvider<int>((ref) => 0);

React의 Zustand store나 Redux slice를 하나 만드는 것과 같다. 이 상자를 위젯이 구독하면, 값이 바뀔 때 그 위젯만 다시 그려진다.

자주 쓰는 Provider 종류

종류 용도 React 비유
Provider 안 바뀌는 값·객체 제공 (서비스, 라우터, 계산값) useMemo / 의존성 주입
StateProvider 단순 값 하나 (bool, int, 텍스트) useState
NotifierProvider 복잡한 상태 + 로직 함께 Zustand store / reducer
FutureProvider 비동기 결과 (API 호출 등) React Query
StreamProvider 스트림 구독 실시간 구독

상태를 읽는 3가지 방법 (ref)

ref는 "다른 상자에 접근하는 리모컨"이다.

방법 언제 React 비유
ref.watch(p) 구독. 값 바뀌면 다시 build build 안에서 화면에 값 표시 useSelector
ref.read(p) 1회만 읽음. 구독 X 버튼 눌렀을 때 등 이벤트 store.getState()
ref.listen(p, cb) 값 바뀔 때 콜백 실행 팝업 띄우기 등 부수효과 useEffect + 구독

주의: build() 안에서는 watch, 이벤트 핸들러에서는 read. 반대로 쓰면 불필요한 재빌드나 구독 누락이 생긴다.

autoDispose — 자동 정리

final myProvider = StateProvider.autoDispose<bool>((ref) => false);

그 상자를 쓰는 화면을 벗어나면 상자를 자동으로 비운다. React 컴포넌트가 언마운트될 때 상태가 사라지는 것과 같다. 페이지 단위 임시 상태(로딩/에러/입력값)에 쓴다.

ProviderScope — 앱을 감싸는 뿌리

runApp(ProviderScope(child: App()));

Riverpod이 동작하려면 앱 최상단을 ProviderScope로 감싸야 한다. Redux의 <Provider store={store}>로 앱을 감싸는 것과 같은 역할.

React → Riverpod 요약

React Riverpod
useState StateProvider
useReducer / Zustand NotifierProvider
useSelector / 구독 ref.watch
store.getState() ref.read
React Query FutureProvider
<Provider store> ProviderScope

관련: "플러터 기초개념" 5번 섹션(Provider와 Riverpod는 왜 쓰나), "routerProvider 패턴" 페이지.