🔍 ConsumerWidget이란?
ConsumerWidget은 flutter_riverpod에서 제공하는 위젯으로, Consumer와 동일한 역할을 하지만 더 간결한 코드 작성을 가능하게 한다.
Consumer vs ConsumerWidget
Consumer | ConsumerWidget | |
사용 방식 | Consumer(builder: (context, ref, child) {...}) | build 메서드에서 ref.watch 사용 가능 |
코드 구조 | StatelessWidget + Consumer 조합 필요 | StatelessWidget을 대체하여 더 간결함 |
위젯 성능 | 특정 부분만 리빌드 가능 | 특정 부분만 리빌드 가능 |
추천 사용처 | 위젯의 특정 부분만 ref.watch가 필요할 때 | 전체 위젯에서 ref.watch를 사용할 때 |
1. Consumer vs ConsumerWidget 사용 추천
✅ Consumer를 사용해야 할 때
- 일부 위젯만 리빌드하고 싶을 때 (예: 특정 Text 위젯만 변경)
- 부모 위젯이 StatelessWidget이나 StatefulWidget일 때
✅ ConsumerWidget을 사용해야 할 때
- 위젯 전체에서 ref.watch가 필요할 경우
- StatelessWidget을 대체하고 싶은 경우
예제) Consumer를 활용하여 Text만 리빌드
(전체 코드 예시는 아래에서 더 설명할 예정)
Consumer(
builder: (context, ref, child) {
final count = ref.watch(counterProvider);
return Text('Count: $count');
},
)
2. 일반 StatelessWidget에서는 ref를 직접 사용할 수 없다!
만약 일반 StatelessWidget에서 ref.watch()를 사용하면 오류가 발생한다.
❌ 일반 StatelessWidget에서 ref를 사용한 경우
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final count = ref.watch(counterProvider); // ❌ 오류 발생
return Scaffold(
appBar: AppBar(title: const Text('Riverpod Counter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Count: $count',
style: const TextStyle(fontSize: 24),
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () => ref.read(counterProvider.notifier).decrement(),// ❌ 오류 발생
icon: const Icon(Icons.remove),
),
IconButton(
onPressed: () => ref.read(counterProvider.notifier).increment(),// ❌ 오류 발생
icon: const Icon(Icons.add),
),
],
),
],
),
),
);
}
}
이 코드에서는 ref.watch(counterProvider)를 사용할 수 없기 때문에 오류가 발생한다.
- StatelessWidget은 ref.watch()를 직접 사용할 수 없다.
- ref는 ConsumerWidget이나 ConsumerStatefulWidget 내부에서만 사용 가능.
해결 방법은?
- 방법1 ) ConsumerWidget을 사용한다.
- 방법2 ) Consumer 위젯을 build 내부에서 감싸서 사용한다.
✅ 방법 1 (ConsumerWidget)
class CounterScreen2 extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider); // count 변경 시 전체 빌드됨
print("CounterScreen2 전체 빌드됨!");
return Scaffold(
appBar: AppBar(title: const Text('Riverpod Counter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Count: $count', // count 변경 시 전체 빌드됨
style: const TextStyle(fontSize: 24),
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () => ref.read(counterProvider.notifier).decrement(),
icon: const Icon(Icons.remove),
),
IconButton(
onPressed: () => ref.read(counterProvider.notifier).increment(),
icon: const Icon(Icons.add),
),
],
),
],
),
),
);
}
}
✅ 방법 2 (Consumer)
class CounterScreen3 extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
print("CounterScreen3 빌드됨!"); //빌드 할 때 한 번만 빌드 됨
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("count 텍스트만 빌드됨!");
return Text(
'Count: $count',
style: const TextStyle(fontSize: 24),
);
},
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () => ref.read(counterProvider.notifier).decrement(),
icon: const Icon(Icons.remove),
),
IconButton(
onPressed: () => ref.read(counterProvider.notifier).increment(),
icon: const Icon(Icons.add),
),
],
),
],
),
),
);
}
}
3. ConsumerWidget vs. ConsumerStatefulWidget, 언제 뭘 써야 할까?
그렇다면 무조건 ConsumerWidget을 써야 할까?
아래 기준을 참고하면 된다.
setState()를 사용하지 않고, Riverpod 상태만 구독할 경우 | ✅ ConsumerWidget |
setState()가 필요하고, 내부적으로 상태를 변경해야 하는 경우 | ✅ ConsumerStatefulWidget |
정리하면?
- 별도의 상태 관리가 필요 없고, Riverpod 상태만 구독하면 ConsumerWidget을 쓰는 게 더 좋다.
- 내부적으로 setState()를 써야 한다면 ConsumerStatefulWidget을 사용해야 한다.
ConsumerStatefulWidget 에 대해서는 다음 글에서 더 자세하게 설명되어 있다.
https://jaslime.tistory.com/50
결론
- ConsumerWidget은 StatelessWidget을 대체하며 ref.watch를 간편하게 사용할 수 있음.
- Consumer는 특정 UI 부분만 리빌드할 때 유용함.
- 프로젝트에 따라 적절한 방식을 선택하여 사용하면 더 깔끔한 코드를 유지할 수 있음!
'개발 > Android' 카테고리의 다른 글
[Flutter] Riverpod 상태관리 - ConsumerStatefulWidget 가이드 (0) | 2025.04.02 |
---|---|
[Flutter] Riverpod 상태관리 - watch vs read 차이 (0) | 2025.04.02 |
[Flutter] 간단한 ToDo앱에서 MethodChannel 응용 (0) | 2025.03.10 |
[Flutter] MethodChannel이란 ? (1) | 2025.03.10 |
[Flutter] Riverpod 상태관리 라이브러리 (0) | 2025.02.20 |