英文:
Merge different states with Riverpod and Freezed
问题
以下是您要翻译的内容:
"I have a page that needs two different API calls.
I am applying the clean architecture to write the code and Riverpod as State Management. Then I am using the Freezed package to map the different states.
How can I combine the different states?
What I would like to achieve is to emit a success state only if both states give me data or emit an error state if one of them is an error, otherwise loading state.
Thanks in advance.
These are the two State classes:
import 'package:freezed_annotation/freezed_annotation.dart';
import '...features/profile/domain/entities/user_profile_entity.dart';
part 'user_profile_details_state.freezed.dart';
@freezed
class UserProfileDetailsState with _$UserProfileDetailsState {
///Initial
const factory UserProfileDetailsState.initial() =
_UserProfileDetailsStateInitial;
///Loading
const factory UserProfileDetailsState.loading() =
_UserProfileDetailsStateLoading;
///Data
const factory UserProfileDetailsState.data(
{required ProfileEntity profileEntity}) = _UserProfileDetailsStateData;
///Error
const factory UserProfileDetailsState.error([String? error]) =
_UserProfileDetailsStateError;
}
import 'package:freezed_annotation/freezed_annotation.dart';
import '....features/profile/domain/entities/user_properties_entity.dart';
part 'user_properties_state.freezed.dart';
@freezed
class UserPropertiesState with _$UserPropertiesState {
///Initial
const factory UserPropertiesState.initial() = _UserPropertiesStateInitial;
///Loading
const factory UserPropertiesState.loading() = _UserPropertiesStateLoading;
///Data
const factory UserPropertiesState.data(
{required UserPropertiesEntity userPropertiesEntity}) =
_UserPropertiesStateData;
///Error
const factory UserPropertiesState.error([String? error]) =
_UserPropertiesStateError;
}
And these are the two notifiers:
import '...core/di/dependency_injection.dart';
import '...core/errors/failures.dart';
import '...core/presentation/riverpod/check_token_notifier.dart';
import '...features/profile/presentation/riverpod/user_profile_details_state.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'user_profile_details_notifier.g.dart';
@riverpod
class UserProfileDetailsNotifier extends _$UserProfileDetailsNotifier {
@override
UserProfileDetailsState build() {
getUserProfileDetailsData();
return const UserProfileDetailsState.initial();
}
Future<void> getUserProfileDetailsData() async {
state = const UserProfileDetailsState.loading();
final userProfileDetailsOrFailure = await ref
.read(userProfileDetailsUseCaseProvider)
.getUserProfileDetailsData();
userProfileDetailsOrFailure.fold((error) {
if (error is TokenFailure) {
ref.read(checkTokenNotifierProvider.notifier).deAuthUser();
return;
}
state = UserProfileDetailsState.error(error.errorMessage);
}, (userProfileDetailsEntity) {
state =
UserProfileDetailsState.data(profileEntity: userProfileDetailsEntity);
});
}
}
import '...core/di/dependency_injection.dart';
import '...core/errors/failures.dart';
import '...core/presentation/riverpod/check_token_notifier.dart';
import '...features/profile/presentation/riverpod/user_properties_state.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'user_properties_notifier.g.dart';
@riverpod
class UserPropertiesNotifier extends _$UserPropertiesNotifier {
@override
UserPropertiesState build() {
getUserPropertiesData();
return const UserPropertiesState.initial();
}
Future<void> getUserPropertiesData() async {
state = const UserPropertiesState.loading();
final userPropertiesOrFailure =
await ref.read(userPropertiesUseCaseProvider).getUserPropertiesData();
userPropertiesOrFailure.fold((error) {
if (error is TokenFailure) {
ref.read(checkTokenNotifierProvider.notifier).deAuthUser();
return;
}
state = UserPropertiesState.error(error.errorMessage);
}, (userPropertiesEntity) {
state =
UserPropertiesState.data(userPropertiesEntity: userPropertiesEntity);
});
}
}
英文:
I have a page that needs two different API calls.
I am applying the clean architecture to write the code and Riverpod as State Management. Then I am using the Freezed package to map the different states.
How can I combine the different states?
What I would like to achieve is to emit a success state only if both states give me data or emit an error state if one of them is an error, otherwise loading state.
Thanks in advance.
These are the two State classes:
import 'package:freezed_annotation/freezed_annotation.dart';
import '...eatures/profile/domain/entities/user_profile_entity.dart';
part 'user_profile_details_state.freezed.dart';
@freezed
class UserProfileDetailsState with _$UserProfileDetailsState {
///Initial
const factory UserProfileDetailsState.initial() =
_UserProfileDetailsStateInitial;
///Loading
const factory UserProfileDetailsState.loading() =
_UserProfileDetailsStateLoading;
///Data
const factory UserProfileDetailsState.data(
{required ProfileEntity profileEntity}) = _UserProfileDetailsStateData;
///Error
const factory UserProfileDetailsState.error([String? error]) =
_UserProfileDetailsStateError;
}
import 'package:freezed_annotation/freezed_annotation.dart';
import '....features/profile/domain/entities/user_properties_entity.dart';
part 'user_properties_state.freezed.dart';
@freezed
class UserPropertiesState with _$UserPropertiesState {
///Initial
const factory UserPropertiesState.initial() = _UserPropertiesStateInitial;
///Loading
const factory UserPropertiesState.loading() = _UserPropertiesStateLoading;
///Data
const factory UserPropertiesState.data(
{required UserPropertiesEntity userPropertiesEntity}) =
_UserPropertiesStateData;
///Error
const factory UserPropertiesState.error([String? error]) =
_UserPropertiesStateError;
}
And these are the two notifiers:
import '...core/di/dependency_injection.dart';
import '...core/errors/failures.dart';
import '...core/presentation/riverpod/check_token_notifier.dart';
import '...features/profile/presentation/riverpod/user_profile_details_state.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'user_profile_details_notifier.g.dart';
@riverpod
class UserProfileDetailsNotifier extends _$UserProfileDetailsNotifier {
@override
UserProfileDetailsState build() {
getUserProfileDetailsData();
return const UserProfileDetailsState.initial();
}
Future<void> getUserProfileDetailsData() async {
state = const UserProfileDetailsState.loading();
final userProfileDetailsOrFailure = await ref
.read(userProfileDetailsUseCaseProvider)
.getUserProfileDetailsData();
userProfileDetailsOrFailure.fold((error) {
if (error is TokenFailure) {
ref.read(checkTokenNotifierProvider.notifier).deAuthUser();
return;
}
state = UserProfileDetailsState.error(error.errorMessage);
}, (userProfileDetailsEntity) {
state =
UserProfileDetailsState.data(profileEntity: userProfileDetailsEntity);
});
}
}
import '...core/di/dependency_injection.dart';
import '...core/errors/failures.dart';
import '...core/presentation/riverpod/check_token_notifier.dart';
import '...features/profile/presentation/riverpod/user_properties_state.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'user_properties_notifier.g.dart';
@riverpod
class UserPropertiesNotifier extends _$UserPropertiesNotifier {
@override
UserPropertiesState build() {
getUserPropertiesData();
return const UserPropertiesState.initial();
}
Future<void> getUserPropertiesData() async {
state = const UserPropertiesState.loading();
final userPropertiesOrFailure =
await ref.read(userPropertiesUseCaseProvider).getUserPropertiesData();
userPropertiesOrFailure.fold((error) {
if (error is TokenFailure) {
ref.read(checkTokenNotifierProvider.notifier).deAuthUser();
return;
}
state = UserPropertiesState.error(error.errorMessage);
}, (userPropertiesEntity) {
state =
UserPropertiesState.data(userPropertiesEntity: userPropertiesEntity);
});
}
}
答案1
得分: 0
您可以创建一个单独的@freezed类,其中将根据您的两个状态收集相应的新字段。在代码中,您可以这样做:
state = CommonState.loading();
UserPropertiesState userProperties;
UserProfileDetailsState userProfileDetails;
final CommonState? state = userProperties.whenOrNull(
orElse: () => null,
data: (properties) => userProfileDetails.whenOrNull(
orElse: () => null,
data: (details) => CommonState.data(properties + details),
),
);
if (state == null) {
// 与错误重复相同
}
您可以在whenOrNull
中使用所需的字段,或将其拆分为if语句。
英文:
You can create a separate @freezed class where the corresponding new fields will be collected based on your two states. In code, you can do this:
state = CommonState.loading();
UserPropertiesState userProperties;
UserProfileDetailsState userProfileDetails;
final CommonState? state = userProperties.whenOrNull(
orElse: () => null,
data: (properties) => userProfileDetails.whenOrNull(
orElse: () => null,
data: (details) => CommonState.data(properties + details),
),
);
if (state == null) {
// same with repeat with error
}
You can use the required fields in whenOrNull
, or split into ifs
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论