flutter

riverpod2.0 codegeneration 학습 1

bakerlee 2023. 5. 1. 17:18

CodeGenerator를 통해 provider를 생성하며 해당 provider들의 생성 및 dispose에 대해서 알아보자 

provider는 여러가지 기준으로 분류할 수 있다. 

분류의 기준 중 하나로 [ 함수 / 클래스 ] 가 있다.

이번 글에서는 함수형 provider들의 생성 및 사용에 대하여 기술한다.  

 

0. observer 

프로바이더들의 생성 및 변경, 삭제 이벤트를 확인하기 위해 observer를 등록하여 로그를 찍도록 하였다. 

ProviderObserver 객체를 상속받아 원하는 형태로 사용 가능하며, 용도에 따라서 여러 observer를 추가하여 사용할 수 있다. 

 

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logger/logger.dart';

class CustomProviderObserver extends ProviderObserver {
  @override
  void didDisposeProvider(ProviderBase<Object?> provider, ProviderContainer container) {
    Logger().i("${provider.name} is disposed : ${provider.runtimeType}");
    super.didDisposeProvider(provider, container);
  }

  @override
  void didAddProvider(ProviderBase<Object?> provider, Object? value, ProviderContainer container) {
    Logger().i("${provider.name} is add : ${provider.runtimeType} , $value ");
    super.didAddProvider(provider, value, container);
  }

  @override
  void didUpdateProvider(
      ProviderBase<Object?> provider, Object? previousValue, Object? newValue, ProviderContainer container) {
    Logger().i("${provider.name} is update : $newValue");
    super.didUpdateProvider(provider, previousValue, newValue, container);
  }
}
ProviderScope getRiverpodMain() {
  return ProviderScope(
    observers: [CustomProviderObserver()],
    child: const MaterialApp(
      home: RiverpodMain(),
    ),
  );
}

 

 

1. provider 

가장 기본적인 형태의 provider 이며 값을 반환한다. 일정한 값을 반환하는 역할만을 수행한다.

리버팟의 생명주기에 따라 캐싱되고 삭제(dispose) 시킨다  

part 'provider.g.dart';

@riverpod
String singleValue(Ref ref) {
  return "This is Value";
}

 

dio, retrofit 클래스와 같이 전역적으로 사용하는 특정 객체를 등록하여 사용하기도 한다. 

I/flutter ( 6447): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 6447): │ #0   CustomProviderObserver.didAddProvider (package:state_management_practice/riverpod/riverpod/obserber/riverpod_observer.dart:13:14)
I/flutter ( 6447): │ #1   runTernaryGuarded (package:riverpod/src/run_guarded.dart:44:7)
I/flutter ( 6447): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter ( 6447): │ 💡 singleValueProvider is add : AutoDisposeProvider<String> , This is Value 
I/flutter ( 6447): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

해당 프로바이더는 watch 하여 사용하는 경우 위와 같이 add 이벤트가 발생하는 것을 확인할 수 있다.

I/flutter ( 6447): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 6447): │ #0   CustomProviderObserver.didDisposeProvider (package:state_management_practice/riverpod/riverpod/obserber/riverpod_observer.dart:7:14)
I/flutter ( 6447): │ #1   runBinaryGuarded (package:riverpod/src/run_guarded.dart:29:7)
I/flutter ( 6447): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter ( 6447): │ 💡 singleValueProvider is disposed : AutoDisposeProvider<String>
I/flutter ( 6447): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

기본적으로 프로바이더는 필요할 때 생성되며, 필요없다고 판단되면 삭제된다. 
watch 혹은 read하면 그때 생성되며, watch하는 곳이 없을 시 자동으로 삭제된다(auto dispose) 
만약 자동으로 삭제되면 안된다면 해당 옵션을 제외하여야 한다. 

이러한 속성은 모든 provider 공통이다. 

추가로 provider호출 시 인자를 추가할 수 있다.
생성 시 다음과 같이 추가할 인자를 명시하고 호출 시 입력하면 된다.

@riverpod
String singleValueWithParam(Ref ref, {required int param}) {
  return "This is Value and param is $param";
}
class _ValueWithParamTestScreen extends ConsumerWidget {
  const _ValueWithParamTestScreen({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final value = ref.watch(singleValueWithParamProvider(param: 512));

    return Scaffold(
      appBar: AppBar(title: const Text("value")),
      body: Center(
        child: Text(value),
      ),
    );
  }
}

 

2. FutureProvider 

Futurue<>를 반환값으로 명시하는 경우 자동으로 FutureProvider로 생성된다.  

Futrue를 반환하는 provider 가 아닌 AutoDisposeFutureProvider를 반환한다. 

@riverpod
Future<String> futureValue(Ref ref) async {
  return Future.delayed(
    const Duration(milliseconds: 500),
    () => "Future is here",
  );
}

 

class _FutureScreen extends ConsumerWidget {
  const _FutureScreen({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final value = ref.watch(futureValueProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text("future"),
      ),
      body: value.when(
        data: (data) => Center(
          child: Text(data),
        ),
        error: (error, stackTrace) => Text(error.toString()),
        loading: () => const Center(child: CircularProgressIndicator()),
      ),
    );
  }
}

 

when 옵션을 사용하여 loading, error, success 상태를 모두 관리 가능하다.

 

 

Code Generation 알아보기 | Riverpod 

 

Code Generation 알아보기 | Riverpod

Code generation is the idea of using a tool to generate code for us.

docs-v2.riverpod.dev

 

BowonLee/state_management_practice: 상태관리 라이브러리 관련 학습 (github.com) 

 

GitHub - BowonLee/state_management_practice: 상태관리 라이브러리 관련 학습

상태관리 라이브러리 관련 학습. Contribute to BowonLee/state_management_practice development by creating an account on GitHub.

github.com