I've been working through some samples using riverpod attempting to correctly separate the logic from the UI layer and business layer. My use case in this instance is that I want to store a custom user profile in Firestore however I'm confused about the provider setup when a ViewModel is involved.
The sample from codewithandrea.com
defines two files per screen, a model (ProfileModel) and a page/pagebuilder(ProfilePageBuilder). At the top of the ProfilePageBuilder it declares a state provider to access the ViewModel. This provider resolves the dependencies required by the ProfileModel.
final profileModelProvider =
StateNotifierProvider.autoDispose<ProfileModel, ProfileState>((ref) {
final authService = ref.watch(authServiceProvider);
final databaseService = ref.watch(databaseProvider)!;
return ProfileModel(
authService: authService, databaseService: databaseService);
});
Now from here, I want the page to have access to the user profile returned from Firestore but the Firestore service returns a Stream<UserProfile>
. My questions are:
This is common question with Firebase and Riverpod.
Whether you want to return a stream is up to you. You don't have to. Here's the line of thought to decide what you want.
I'll use riverpod 2.0 with code generation syntax, but these all can be written without codegen if you prefer, just more verbose.
One way is to use a BehaviorSubject from package:rxdart
which remembers only the last value of a stream.
import 'package:rxdart/rxdart.dart';
@riverpod
BehaviorSubject<UserProfile> userProfileSubject(
UserProfileStreamRef ref,
String userId,
/*more params if you want*/) {
final firebaseStream = ...
// goal of this provider is to get the stream
// from firebase and convert to a BehaviorSubject
return BehaviorSubject()
..addStream(firebaseStream);
}
@riverpod
UserProfile? userProfile(UserProfileRef ref) {
// this provider listens to the behavior subject
// and refreshes itself when the value changes
// so the dependent providers and widgets can react
final subject = ref.watch(userProfileSubjectProvider(userId, ...));
// if no params to provider
//final subject = ref.watch(userProfileSubjectProvider);
// when there's a new value, invalidate self
// so we re-run this and return the new value
subject.doOnData((newProfile) {ref.invalidateSelf();});
// note that subject can have a null value until
// first value is emitted from the stream or stream emits a null.
// your UI must handle this case.
return subject.value;
}
now your view model or whatever can depend on this userProfileProvider
or use it in a ConsumerWidget
directly.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.