
지난 시간에 했던 제너레이션된 코드를 분석해 보는 타임~~~
그 전에 String뿐 아니라 async로도 값을 반환할 수 있다는 것도 확인해보자!
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'code_generation_provider.g.dart';
// code_generation이 riverpod에 추가가 된 이유
// (1) 어떤 Provider를 사용할지 결정할 고민 할 필요가 없도록!
// Provider, FutureProvider, StreamProvider
// - 어떤 종류의 Provider를 쓸지 고민하지 않아도 code_generation을 쓰면 riverpod에서 알아서 결정해줌.
// - StateNotifierProvider는 명시적으로 code_generation 할 수 있음.
// (1)-1. Provider 생성
final _testProvider = Provider<String>((ref) => 'Hello Code Generation');
// (1)-2. riverpod 어노테이션 작성하고 일반 함수로 작성
// (1)-3. <String>을 반환받고 싶으니까 String으로 작성해주고
// (1)-4. ref를 받아준다 => 어떻게? => 현재 함수 이름(첫글자는 대문자로) + Ref 변수명
// (1)-5. { } 함수 안에 return 반환해주기
// (1)-6. 터미널에 flutter pub run build_runner build
String gState(GStateRef ref) {
return 'Hello Code Generation';
}
// Future값 넣어보기!
// flutter pub run build_runner build 까지 해주기
Future<int> gStateFuture(GStateFutureRef ref) async {
await Future.delayed(const Duration(seconds: 3));
return 10;
}
CodeGenerationScreen으로 가서 받아주기

저장하고 실행해보면...

Loading 됐다가 3초 후에 아래와 같이 잘 나오는 걸 볼 수 있다.
이렇게 나오는 이유는...?
FutureProviderScreen로 가서 보면 FutureProvider를 쓸 때,
state.when을 써서 반환해줘야 된다고 해둠.

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) {
final state1 = ref.watch(gStateProvider);
final state2 = ref.watch(gStateFutureProvider);
return DefalutLayout(
title: 'CodeGenerationScreen',
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch
children: [
Text('State1 : $state1'),
state2.when(
// 'State2 : $data'
data: (data) {
return Text(
data.toString(),
textAlign: TextAlign.center,
);
},
error: (err, stack) => Text(
err.toString(),
),
loading: () => const Center(
child: CircularProgressIndicator(),
),
),
],
),
);
}
}
저장하고 앱 재실행 후, CodeGenerationScreen 버튼 눌러서 다시 들어가보면...

로딩이 3초간 떴다가 10이라는 숫자가 나온다.

드래그 된 부분은 아래와 같이 바꿔준다.

그러면 State2 : 10 이라고 나오는 걸 볼 수 있다.
이를 통해서 FutureProvider도 쓸 수 있다는 걸 증명해냄!!!
그럼 원래 해보려고 했던 제너레이션된 코드 분석을 본격적으로 해보자~~~

code_generation_provider.g.dart 파일을 봐보자.
원래는 Provider라는 키워드만 사용해서 생성을 했었음.
그런데 AutoDisposeProvider라고 적혀있음...
AutoDispose 이거 auto_dispose_modifier 할 때 배웠었음!
autoDispose를 어떤 프로바이더든 등록해주면 사용되지 않는 순간에는 삭제가 됐음.

일반적으로 @riverpod 으로 code_generation 하면
AutoDispose 키워드가 자동으로 붙음.
그럼 AutoDispose를 쓰지 않고 그냥 일반 Provider를 생성하고 싶을 땐???

code_generation_provider.g.dart 보면 다른 건 다 AutoDisposeFutureProvider인데,
이것만 FutureProvider로 만들어진 걸 볼 수 있다.
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'code_generation_provider.g.dart';
// code_generation이 riverpod에 추가가 된 이유
// (1) 어떤 Provider를 사용할지 결정할 고민 할 필요가 없도록!
// Provider, FutureProvider, StreamProvider
// - 어떤 종류의 Provider를 쓸지 고민하지 않아도 code_generation을 쓰면 riverpod에서 알아서 결정해줌.
// - StateNotifierProvider는 명시적으로 code_generation 할 수 있음.
// (1)-1. Provider 생성
final _testProvider = Provider<String>((ref) => 'Hello Code Generation');
// (1)-2. riverpod 어노테이션 작성하고 일반 함수로 작성
// (1)-3. <String>을 반환받고 싶으니까 String으로 작성해주고
// (1)-4. ref를 받아준다 => 어떻게? => 현재 함수 이름(첫글자는 대문자로) + Ref 변수명
// (1)-5. { } 함수 안에 return 반환해주기
// (1)-6. 터미널에 flutter pub run build_runner build
String gState(GStateRef ref) {
return 'Hello Code Generation';
}
// Future값 넣어보기!
// flutter pub run build_runner build 까지 해주기
Future<int> gStateFuture(GStateFutureRef ref) async {
await Future.delayed(const Duration(seconds: 3));
return 10;
}
// AutoDispose를 쓰지 않고 일반 Provider를 생성하기
// 이땐 대문자 + () => @Riverpod()
// 그리고 이 대문자 Riverpod 어노테이션은 ()여기에 파라미터를 하나 받음!
// 그 파라미터는 => keepAlive (살려둬라)
// keepAlive의 기본값은 false
// AutoDispose가 안 붙는 Provider(일반 Provider)를 만들고싶을 땐 true
(
keepAlive: true,
)
Future<int> gStateFuture2(GStateFuture2Ref ref) async {
await Future.delayed(const Duration(seconds: 3));
return 10;
}
// (2) Parameter => 리버팟에서는 Family
// Family 파라미터를 일반 함수처럼 사용할 수 있도록!
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) {
final state1 = ref.watch(gStateProvider);
final state2 = ref.watch(gStateFutureProvider);
final state3 = ref.watch(gStateFuture2Provider);
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(),
),
),
],
),
);
}
}
앱을 재실행하고, CodeGenerationScreen 버튼을 눌렀을 때


state1은 그대로 바로 나오고
state2, state3은 로딩이 되고 값이 나온다.

다시 뒤로 갔다가 들어가면...

state2만 렌더링 됐다가 뜨고,
state3은 다시 렌더링되지 않고 바로 뜨는 걸 볼 수 있다.
왜냐면... keepAlive: true 해뒀기 때문!