드디어 riverpod 에 대한 마지막 글을 적어 볼려고 한다. 이전 내용으로도 riverpod 을 사용하는데 기본적인 내용은 다 들어갔지만, 좀 더 멋있게 사용하고 싶다면 이번 내용을 참고하길 바란다.
지금 까지 provider
는 기존에 정의된 내용의 정보와 상태를 가지고 오는것에만 특화 되어 있었다. 하지만 종종 호출하는 쪽에서 원하는 정보만 참고하기 위해 정보(파라미터)를 전달해야 하는 경우가 있다. 이 경우 사용하는 것이 family
수식어 이다.
통상적인 family 수식어의 사용 예는 다음과 같다.
사용법은 예제로 확인 해 보자.
email, password 정보를 입력 받아서 login 을 수행하는 FutureProvider 가 있다고 하자.
class LoginInfo {
String email;
String password;
LoginInfo(this.email, this.password);
}
final doEmailLogin = FutureProvider.family<bool, LoginInfo>((ref, loginInfo) async {
String email = loginInfo.email;
String password = loginInfo.password;
return await dio.get('https://myApi.login', data: {'email', email, 'password', password});
});
여기서 return 부분은 login API 를 호출하고 login 여부를 bool 값으로 반환한다고 가정하자.
family 를 이용하여 provider는 LoginInfo 라는 파라미터를 전달 받을 수 있게 된다.
여기서 family 수식어 사용법은 좀 더 자세히 알아보면, family<반환 타입, 전달 타입>
으로 family 타입을 선언하고, provider 의 인수로 전달되는 함수에 ref 객체와 전달되는 객체을 전달하면 된다.
전달되는 파라미터는 하나가 최대이기에 여러 인수를 한꺼번에 넘기기 위해서는 LoginInfo 와 같이 객체화 시켜서 넘겨주면 된다.
⚠️ 주의
사실 여기서 사용할 수 있는 매개변수는 컴퓨터 주요 자료형 (bool, int, double, String), provider, 그리고==
나hashCode
를 오버라이드 할 수 있는 immutable 객체이어야 한다. immutable 객체를 사용하기 위해서는Freezed
또는equatable
을 사용해 주어야 하지만 이번 예제에서는 다루지 않았다.
해당 내용에 대해서는 기회가 되면 추후 따로 글을 작성하도로 하겠다.
이 provider 의 사용 방법은 기존과 동일하게, ref.watch
를 이용하면 되지만, 호출시 인수를 같이 넘겨주면 된다.
Widget build(BuildContext context, WidgetRef ref) {
LoginInfo loginInfo = LoginInfo('test@abc.com', '1q2w3e4r');
final response = ref.watch(doEmailLogin(loginInfo));
}
지금까지 provider 를 사용하면서 느꼈을 지도 모르겠지만, provider도 결국은 변수 이다. 변수는 선언을 하고 더이상 사용하지 않을 경우 메모리에서 해제 시켜주는것이 좋다. 이 때 사용하는 것이 autoDispose
이다.
통상적인 autoDispose 의 유즈 케이스는 다음과 같다.
위와 같은 경우 autoDispose 를 사용해주면 된다.
사용법은 간단하게 provider 뒤에 .autoDispose 를 붙여주면 된다.
final userProvider = StreamProvider.autoDispose<User>((ref) {
});
또한 autoDispse
와 family
수식어는 함께 사용 할 수 있다.
final userProvider = StreamProvider.autoDispose.family<User, String>((ref, id) {
});
ProviderObserver
는 ProviderContainer 의 변화를 관찰하여, provider 의 상태를 모니터링 할 수 있게 해줍니다. providerObserver 를 통해 현재 앱에서 사용되는 상태(state)들을 모니터링 할 수 있고, 문제 발생시 원인을 파악하는데 도움을 줄 수 있다
ProviderOberver 클래스를 상속 받아서 사용할 수 있고, 아래 3가지 메소드를 override 해서 사용할 수 있다.
class Logger extends ProviderObserver {
void didUpdateProvider(
ProviderBase provider,
Object? previousValue,
Object? newValue,
ProviderContainer container,
) {
print('''
{
"provider": "${provider.name ?? provider.runtimeType}",
"newValue": "$newValue"
}''');
}
}
void main() {
runApp(
ProviderScope(observers: [Logger()], child: const MyApp()),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(home: Home());
}
}
final counterProvider = StateProvider((ref) => 0, name: 'counter');
class Home extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Scaffold(
appBar: AppBar(title: const Text('Counter example')),
body: Center(
child: Text('$count'),
),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: const Icon(Icons.add),
),
);
}
}
잘봤습니다