Riverpod watch vs read 차이와 UI 빌드 영향 분석
🔍 watch vs read 차이
watch (ref.watch)
- ref.watch(provider)를 사용하면 해당 provider의 값이 변경될 때마다 UI가 자동으로 리빌드됨.
- 주로 UI에 실시간으로 반영해야 하는 상태 값을 구독할 때 사용.
read (ref.read)
- ref.read(provider)는 현재 상태 값만 한 번 읽고 끝.
- 이후 provider 값이 변경되더라도 UI가 리빌드되지 않음.
- 주로 이벤트 기반 로직 (ex. 버튼 클릭 시 상태 변경)에서 사용.
사용 방식 리빌드 여부 설명
ref.watch(provider) | ✅ 리빌드됨 | provider의 값이 변경될 때마다 UI가 다시 빌드됨. (자동 감지) |
ref.read(provider) | ❌ 리빌드 안됨 | 한 번만 읽고 이후 변경이 있어도 UI에 영향을 주지 않음. |
ref.watch(provider.notifier) | ❌ 리빌드 안됨 | notifier 객체 자체는 변하지 않음. (상태 변경 감지 X) |
ref.read(provider.notifier) | ❌ 리빌드 안됨 | notifier의 메서드를 실행하지만, UI 리빌드는 일어나지 않음. |
🛠 예제 코드 (UI 빌드 확인용)
아래 코드를 실행하면 watch와 read의 차이를 명확하게 확인할 수 있습니다.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
/// 상태 관리 (카운터)
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() {
state++;
}
void decrement() {
state--;
}
}
final counterProvider = StateNotifierProvider<CounterNotifier, int>(
(ref) => CounterNotifier(),
);
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("🔄 Counter 값만 빌드됨! (Text 위젯)");
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(); // ✅ read 사용 (UI 리빌드 방지)
},
icon: const Icon(Icons.remove),
),
IconButton(
onPressed: () {
print("➕ Increment 버튼 클릭!");
ref.watch(counterProvider.notifier).increment(); // ❌ 잘못된 watch 사용
},
icon: const Icon(Icons.add),
),
],
);
},
),
],
),
),
);
}
}
실행 결과 및 분석
터미널 출력 결과를 보면 어떤 부분이 다시 빌드되는지 확인할 수 있습니다.
🖥️ CounterScreen 전체가 빌드됨!
🔄 Counter 값만 빌드됨! (Text 위젯)
🔄 버튼 UI가 빌드됨!
➕ Increment 버튼 클릭!
🔄 Counter 값만 빌드됨! (Text 위젯)
➖ Decrement 버튼 클릭!
🔄 Counter 값만 빌드됨! (Text 위젯)
👉 버튼 UI(Row)는 처음 한 번만 빌드되고 이후에는 변경되지 않음!
👉 오직 Text 위젯만 리빌드됨! (watch(counterProvider) 때문)
❌ ref.watch(counterProvider.notifier)를 사용하면 안 되는 이유
- counterProvider.notifier 자체는 변하지 않으므로 watch를 해도 UI가 리빌드되지 않음.
Consumer(
builder: (context, ref, child) {
final count = ref.watch(counterProvider.notifier);
print("🔄 Counter 값만 빌드됨! (Text 위젯)");
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(); // ✅ read 사용 (UI 리빌드 방지)
},
icon: const Icon(Icons.remove),
),
IconButton(
onPressed: () {
print("➕ Increment 버튼 클릭!");
ref.watch(counterProvider.notifier).increment(); // ❌ 잘못된 watch 사용
},
icon: const Icon(Icons.add),
),
],
);
},
),
위와 같은 코드로 실행을 하면, 아래와 같이 버튼 클릭한 것만 인식을 하고, 그 후 다시 빌드하지 않아 UI 변경은 없다.
CounterScreen 전체가 빌드됨!
🔄 Counter 값만 빌드됨! (Text 위젯)
🔄 버튼 UI가 빌드됨!
➕ Increment 버튼 클릭!
➖ Decrement 버튼 클릭!
때문에 Text("Count : $count)를 실제 화면에서 보면 아래와 같은 화면이 나타난다.
- watch할 때는 counterProvider 자체를 watch해야 한다 !
✅ 올바른 코드 수정 방법
Consumer(
builder: (context, ref, child) {
final count = ref.watch(counterProvider); // ⭕ 올바른 사용
return Text(
'Count: $count',
style: const TextStyle(fontSize: 24),
);
},
),
.
.
.
IconButton(
onPressed: () {
print("➕ Increment 버튼 클릭!");
ref.read(counterProvider.notifier).increment(); // ⭕ 올바른 사용
},
icon: const Icon(Icons.add),
),
'개발 > Android' 카테고리의 다른 글
[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 |
[Flutter] Riverpod 상태관리 라이브러리 (0) | 2025.02.20 |