-
|
Imagine you have an @riverpod
class MyNotifier extends _$MyNotifier {
MyService get _service => ref.read(myServiceProvider);
@override
FutureOr<MyState> build() async {
final params = await .....
final data = await _service.doSomething(params, progressCallback: (message) {
// handle progress change
})
final transformedData = await ....(data)
return MyState(transformedData)
}
}The build can be long so the notifier can stay in Now we can pass a Here are some options I've thought so far. Hacky and ugly workaround: string to intWe define a constant list for messages: const messagesList = {
'Fetching X',
'Preprocessing Y',
'Doing some other thing',
....
}In notifier's build we convert message to his index and divide it to scale in progress range: ...
final data = await _service.doSomething(params, progressCallback: (message) {
final messageIdx = messagesList.index(message);
state = AsyncLoading(progress: messageIdx / 10.)
})
...And in UI: ...
case AsyncLoading(:final progress?):
final message = messagesList.valueAt((progress*10).round())It works in theory but it has tons of bad practices and incovenients. A second notifier for loading progress only@riverpod
class LoadingMessageNotifier extends _$LoadingMessageNotifier {
@override
String? build() => '';
void setMessage(String message) {
state = message;
}
}
@riverpod
class MyNotifier extends _$MyNotifier {
MyService get _service => ref.read(myServiceProvider);
@override
FutureOr<MyState> build() async {
final params = await .....
final data = await _service.doSomething(params, progressCallback: (message) {
ref.read(loadingMessageProvider.notifier).setMessage(message);
})
final transformedData = await ....(data)
return MyState(transformedData)
}
}In UI when state is
|
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
|
I propose not to vomit out AI schlop to give out help; if a user wants the schlop, it'd just ask gemini et. al. Instead, I think a user is here to ask actual humans. Thanks. You've already shown my proposal above, but I want to address this:
You probably fear this is "too much boilerplate", or "too much complicated", but imho it isn't. If my guess is right, you're probably underestimating the problem. In a nutshell, you do need to keep track of which state you're in, and you need to keep track which was the last state that "went well", and if (and which) an error occurred in between. That's the true power of For example (with - honestly - not that much code) you get to express with a single pattern-matchable variable: "yeah I'm loading, since I'm retrying to refresh this value because it errored, but hey I still have the first value which was OK". Code speaks volumes: @freezed
sealed class Step with _$Step{
const factory Step.one() = StepOne;
const factory Step.two() = StepTwo;
const factory Step.three() = StepThree;
const factory Step.final(int value) = StepFinal;
}
@riverpod
class SomethingNotifier extends _$SomethingNotifier {
late Some dependency;
Stream<Step> build {
dependency = ref.watch(userIdProvider).requireValue; // !
return _init(dependency);
}
Stream<Step> _init(Some dependency) async* {
final finalStep = await _service.doSomething(params, progressCallback: (step) {
yield step;
});
yield finalStep; // this contains .value
}
// other side effects, maybe, idk
} |
Beta Was this translation helpful? Give feedback.
I propose not to vomit out AI schlop to give out help; if a user wants the schlop, it'd just ask gemini et. al. Instead, I think a user is here to ask actual humans. Thanks.
You've already shown my proposal above, but I want to address this:
You probably fear this is "too much boilerplate", or "too much complicated", but imho it isn't. If my guess is right, you're probably underestimating the problem.
In a nutshell, you do need to keep track of which state you're in, and you need to keep track which was the last state that "went well", and if (and which) an e…