Sealed classes / union types and copyWith #939
Unanswered
net-funkyrobot
asked this question in
Q&A
Replies: 1 comment
-
Does something like this help? This is the pattern I'm currently using @freezed
sealed class Result<D, F> with _$Result<D, F> {
const factory Result.success(D data) = Success<D, F>;
const factory Result.error(F failure) = Error<D, F>;
}
@freezed
sealed class Failure with _$Failure {
const factory Failure.unauthenticated({
@Default(
"You need to be authenticated to perform this action. Please log in and try again.")
String description,
}) = UnauthenticatedError;
const factory Failure.serverError({
@Default("We encountered an issue with our server. Please try again later.")
String description,
}) = ServerError;
// More failure types
}
@freezed
sealed class NewsState with _$NewsState {
const factory NewsState.articles(List<NewsArticle> articles) = NewsData;
const factory NewsState.loading() = Loading;
const factory NewsState.error(Failure failure) = NewsFailure;
}
@riverpod
class News extends _$News {
@override
NewsState build() {
return const NewsState.articles([]);
}
Future<void> fetchArticles(String updatedProperty) async {
state = const NewsState.loading();
final articleService = ref.read(articleServiceProvider);
final articlesResult = Result<List<NewsArticle>, Failure> articleResult = await articleService.fetchArticles();
state = switch (articlesResult) {
Success() => NewsState.articles(articlesResult.data.map((article) => article.copyWith(oldProperty: updatedProperty))),
Error() => NewsState.error(articlesResult.failure),
};
}
} you can also use the updated syntax: state = switch (articlesResult) {
Success(:final data) => NewsState.articles(data.map((article) => article.copyWith(oldProperty: updatedProperty))),
Error(:final failure) => NewsState.error(failure),
}; and then in your ui you can do something like: newsArticles = ref.watch(newsProvider)
switch(newsArticles) {
NewsData(:final data) => data.map((article) => Text(article.title)),
Loading() => const CircularProgressIndicator(),
NewsFailure(:final failure) => const Text(failure.description)
} |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
The new matching and destructuring in Dart 3 for sealed classes works great for consumers of freezed models. In consuming Flutter widgets you can use switch case matching to handle all possible states of your freezed model and often consuming widgets only need a subset of your models fields.
However in producers, like a BLoC / Cubit / Riverpod state notifier, you often want to transform the existing state using
copyWith
. I'm finding this very difficult because your BLoC never knows what state your model is in, whether it is.loading
or.data
.Is the only way to do this using
is
andas
to cast the model into the state you believe it should be in? The freezed documentation discourages use ofis
andas
.Are there more elegant ways of doing this that I'm not aware of?
Additionally, in a consumer, you sometimes want to match the model state but work with the model instance as a whole and not have to destructure every model attribute in order to work with it.
Is there a way to do this with matching in Dart 3?
I'd also like to say a big thanks to the freezed maintainers. Freezed is a big part of what has made Flutter so great, for me at least.
Beta Was this translation helpful? Give feedback.
All reactions