Consumer 위젯이 왜 필요한가???
CodeGenerationScreen에서 state5는 Increment, Decrement에 의해 변경되는 값임.
그러면 이 버튼들을 눌렀을 때 정말로 Widget build 함수가 실행되는지 print를 찍어서 확인해보자.

지금 state5와 관련된 버튼들만 눌렀음.
즉, state5만 변경하고 있는데 State1, State2, State3, State4 정보를 갖고 있는
위젯들까지 전부 다 build 되고 있음!
그러니까 이 build가 불리는 대상이 DefalutLayout 전체 위젯이라는 건데...
그럼... 비효율적이겠지?
어떻게 효율적으로, 국소적으로 변경할 수 있을까???
(State5에 대한 변경이 있으면 State5만 변경되게)

이렇게 위젯을 따로 일일이 만들어도 되지만, 코드 템플릿이 많아지는 것 역시 비효율적임...
결국 정말 쓰고싶은 건 return Text('State5: $state5'); 이 한 줄인데!!!
그래서 이렇게 하지 말고, 그냥 새로 위젯을 제공해주겠다... 라는
생각으로 탄생한 게 바로 Consumer 위젯이다.

그리고 Consumer 위젯은 다음과 같이 3가지 파라미터를 순서대로 받는다.

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_study/layout/defalut_layout.dart';
import 'package:riverpod_study/riverpod/code_generation_provider.dart';
class CodeGenerationScreen extends ConsumerWidget {
const CodeGenerationScreen({super.key});
Widget build(BuildContext context, WidgetRef ref) {
print('build');
final state1 = ref.watch(gStateProvider);
final state2 = ref.watch(gStateFutureProvider);
final state3 = ref.watch(gStateFuture2Provider);
final state4 = ref.watch(gStateMultiplyProvider(number1: 10, number2: 20));
// final state5 = ref.watch(gStateNotifierProvider);
return DefalutLayout(
title: 'CodeGenerationScreen',
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('State1 : $state1'),
state2.when(
data: (data) {
return Text(
'State2 : $data',
textAlign: TextAlign.center,
);
},
error: (err, stack) => Text(
err.toString(),
),
loading: () => const Center(
child: CircularProgressIndicator(),
),
),
state3.when(
data: (data) {
return Text(
'State3 : $data',
textAlign: TextAlign.center,
);
},
error: (err, stack) => Text(
err.toString(),
),
loading: () => const Center(
child: CircularProgressIndicator(),
),
),
Text('State4 : $state4'),
// const _StateFiveWidget(), // Text('State5 : $state5'),
Consumer(
builder: (context, ref, child) {
final state5 = ref.watch(gStateNotifierProvider);
return Text('State5: $state5');
},
),
Row(
children: [
ElevatedButton(
onPressed: () {
// ref.read => 단일적/일시적으로 Provider를 불러올 때 사용
// 함수를 불러올 때(Provider 그 자체 StateNotifier)는 Provider.notifier 해줘야함.
ref.read(gStateNotifierProvider.notifier).increment();
},
child: const Text('Increment'),
),
ElevatedButton(
onPressed: () {
ref.read(gStateNotifierProvider.notifier).decrement();
},
child: const Text('Decrement'),
),
],
),
// invalidate() => 유효하지 않게 하다
// 즉, state를 더 이상 유효하지 않게 해서 초기 상태로 되돌리는 역할!
ElevatedButton(
onPressed: () {
ref.invalidate(gStateNotifierProvider);
},
child: const Text('Invalidate'),
),
],
),
);
}
}
class _StateFiveWidget extends ConsumerWidget {
const _StateFiveWidget({super.key});
Widget build(BuildContext context, WidgetRef ref) {
final state5 = ref.watch(gStateNotifierProvider);
return Text('State5: $state5');
}
}
앱 재실행하고 CodeGenerationScreen 화면으로 들어가면...

build가 되고, Future builder 들이 끝나서 build가 또 불렸음.
다음에 또 build가 불리는지 확인해보자.
Increment, Decrement, Invalidate 버튼을 눌러보자.

아무리 버튼을 눌러서 숫자를 바꾸고 변화를 줘도 build 출력 안됨!
❓ 왜???
👉 Consumer로 final state5 = ref.watch(gStateNotifierProvider);
이 ref.watch라는 값을 감싸는 순간 여기서 변경이 있을 때,
상위의 build가 재실행되는 게 아니라
Consumer 내의 builder: (context, ref, child) { } 함수가 재실행이 되는 것.
이를 확인하기 위해 여기서 print를 찍어보자.


즉, Consumer 위젯 안에서 정확히 리스닝하고 싶은 것만 리스닝하면서
이 값이 필요한 위젯들만 부분적으로 렌더링을 할 수 있다.
그러면 렌더링 효율도 좋아지겠지?!
그다음 child 위젯....
child 위젯은 Consumer 위젯에 제공해줄 수 있는 한가지 요소!
Consumer 위젯의 child 파라미터에 입력된 위젯이
Consumer 위젯에 builder 파라미터 안에 있는 child 파라미터에 그대로 제공됨!

hello가 붙어서 나옴.
이렇게 넣어줘야 하는 이유는?
새로 렌더링하는 요소가 부분적일 때...
그러니까 builder 함수 안에서 새로 렌더링해줘야 하는 부분은 Text('State5: $state5') 이거임!
근데 이게 새로 렌더링되기 위해서 그 아래에 있는 다른 위젯들까지 새로 렌더링할 필요는 없겠지??
그러니까 이 Consumer 위젯 안에서만 부분적으로 렌더링시키는 기능에다가
Consumer 위젯의 builder 함수 안에서
child(child 파라미터에 입력된) 위젯은 단 한번 렌더링됨.
렌더링하는데 컴퓨터 퍼포먼스가 많이 필요한 위젯들을
builder 안에 넣어줘야하는데, 퍼포먼스가 많이 필요하고 빌드가 다시 실행되도
변경사항이 딱히 필요없는 위젯들을 Consumer의 child 파라미터 안에 넣어주면,
builder 안에 child 파라미터로 다시 되받아서
if (child != null) child 이 위젯은 builder 함수가 재실행되더라도
다시 실행되지 않도록 할 수 있는 거임.
즉, if (child != null) child, 이건 한 번만 빌드되고
나머지만 새로 계속 빌드됨.