Riverpod에서 watch vs read 차이점 정리 및 UI 리빌드 분석
Flutter에서 상태 관리를 하다 보면 Riverpod을 선택하는 경우가 많다. 기능적으로 강력하지만, 처음 접했을 땐 watch와 read의 차이로 인해 의도치 않게 UI가 안 바뀌거나 과도하게 빌드되는 상황이 발생하기도 한다.
이 글에서는 실제 사용 중 겪었던 경험을 바탕으로 watch와 read의 차이를 구체적인 예제와 함께 정리해봤다.
ref.watch와 ref.read의 핵심 차이
사용 방식 UI 리빌드 여부 설명
| ref.watch(provider) | ✅ 리빌드됨 | 상태 변경 시 UI 자동 리빌드 |
| ref.read(provider) | ❌ 리빌드 안됨 | 현재 값만 읽고 이후 변경 무시 |
| ref.watch(provider.notifier) | ❌ 리빌드 안됨 | notifier 자체는 변하지 않기 때문에 감지 불가 |
| ref.read(provider.notifier) | ❌ 리빌드 안됨 | 메서드 실행용으로만 사용 |
실전 예제
final counterProvider = StateNotifierProvider<CounterNotifier, int>(
(ref) => CounterNotifier(),
);
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
void decrement() => state--;
}
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("CounterScreen 전체 빌드");
return Scaffold(
appBar: AppBar(title: const Text('Riverpod Counter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Consumer(
builder: (context, ref, child) {
final count = ref.watch(counterProvider);
print("Text 위젯 빌드 (count: $count)");
return Text('Count: $count', style: const TextStyle(fontSize: 24));
},
),
const SizedBox(height: 20),
Consumer(
builder: (context, ref, child) {
print("버튼 UI 빌드");
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () {
print("Decrement 클릭");
ref.read(counterProvider.notifier).decrement();
},
icon: const Icon(Icons.remove),
),
IconButton(
onPressed: () {
print("Increment 클릭");
ref.read(counterProvider.notifier).increment(); // ✅ read 사용
},
icon: const Icon(Icons.add),
),
],
);
},
),
],
),
),
);
}
}
실행 결과 로그
CounterScreen 전체 빌드
Text 위젯 빌드 (count: 0)
버튼 UI 빌드
Increment 클릭
Text 위젯 빌드 (count: 1)
Decrement 클릭
Text 위젯 빌드 (count: 0)
- 버튼 UI는 처음 한 번만 빌드됨
- Text 위젯만 상태 변경에 따라 리빌드됨
잘못된 사용 예시
final count = ref.watch(counterProvider.notifier); // ❌ 잘못된 감지 대상
notifier는 객체 자체가 변하지 않기 때문에 상태 변화가 있어도 UI는 갱신되지 않는다. 실제 상태는 내부의 state 값이므로, 이를 감지하려면 ref.watch(counterProvider)처럼 상태 자체를 감시해야 한다.
올바른 사용 방법
final count = ref.watch(counterProvider); // ✅ 올바른 감시
ref.read(counterProvider.notifier).increment(); // ✅ 이벤트 발생 시 사용
이렇게 사용하면 UI는 필요한 부분만 리빌드되고, 나머지는 효율적으로 유지된다.
마무리
Riverpod을 쓸 때 watch와 read의 개념을 정확히 알고 쓰는 것이 중요하다.
watch는 상태 감시용, read는 이벤트용이라고 구분하면 이해가 빠르다.
상태 변경이 UI에 반영되어야 한다면 watch, 단순히 메서드 실행이나 값 확인이 목적이라면 read를 선택하자.
'개발 > Android' 카테고리의 다른 글
| [Flutter 오류 해결] Gradle & Java 버전 호환 이슈 해결 방법 (feat. Java 21 → 17 다운그레이드) (1) | 2025.04.17 |
|---|---|
| [Flutter] Riverpod 상태관리 - ConsumerStatefulWidget 가이드 (0) | 2025.04.02 |
| [Flutter] Riverpod 상태관리 - ConsumerWidget 가이드 (0) | 2025.04.02 |
| [Flutter] 간단한 ToDo앱에서 MethodChannel 응용 (0) | 2025.03.10 |
| [Flutter] MethodChannel이란 ? (1) | 2025.03.10 |