[Flutter] Family로 파라미터 전달 받기

겨레·2024년 7월 25일

[Flutter] Riverpod v2

목록 보기
4/7

Family Modifier를 쓸 수 있는 방법을 알아보자!



일단 그 전에 어떻게 Provider에서 Family를 사용했었는지 먼저 알아보자...


① FamilyProvider 생성
FamilyProvider 생성해주고, 만약에 number1 * number2 곱한 값을 반환하고 싶다고 가정하자.

①-1. Provider옆에 .family 키워드 추가
①-1. Provider 두 번째 < > 제너릭에 어떤 값을 넣어줄지 추가
그런데 이런 식으로 1개밖에 값을 못 넣는다.
그럼 원하는 걸 못하게 되는데, 이럴 땐 어떻게 해야하느냐!
클래스를 만든다!!!

그럼 int가 아니고 Parameter겠지???
Parameter라는 class로 바꿔준다.

그러면 이제 정상적으로 int 값을 반환할 수 있다.

하지만 이렇게 하게 되면 코드가 길어진다.
단순히 number1과 number2를 Provider 안에 Family로 전달하고 싶었던건데...!
이런 문제를 @ 어노테이션이 해결해준다.

그런데 number1 랑 number2를 어디에서 받을까??

이제 더 이상 위에처럼 class 선언할 필요 없이
일반 함수를 선언할 때처럼 받아주면 됨.


그러니까...

이 방식이랑

아래 이 방식이랑 riverpod에서 결국 같은 방식인거임!



flutter pub run build_runner build 터미널에다가 코드 제너레이션 돌려주기!


  • code_generation_provider.dart 코드
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 파라미터를 일반 함수처럼 사용할 수 있도록!
class Parameter {
  final int number1;
  final int number2;

  Parameter({
    required this.number1,
    required this.number2,
  });
}

// (2)-1. Provider 생성
final _testFamilyProvider = Provider.family<int, Parameter>(
    (ref, Parameter) => Parameter.number1 * Parameter.number2);

// (2)-2. riverpod 어노테이션 작성
// 파라미터 안에 값을 전달만 해주면 일반 Family처럼 riverpod을 사용할 수 있다!

int gStateMultiply(
  GStateMultiplyRef ref, {
  required int number1,
  required int number2,
}) {
  return number1 * number2;
}



② state 불러오기
CodeGenerationScreen으로 가서 state4 불러오자!

  • code_generation_screen.dart 코드
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);
    final state4 = ref.watch(gStateMultiplyProvider(number1: 10, number2: 20));

    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'),
        ],
      ),
    );
  }
}

저장하고 앱을 재실행하면 state4도 잘 나온다.

이러한 장점을 고려해서 code_generation이 유리한 경우라면 code_generation을 사용해서 Provider를 사용하자!

profile
호떡 신문지에서 개발자로 환생

0개의 댓글