Merge不同的状态与Riverpod和Freezed。

huangapple go评论62阅读模式
英文:

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 &#39;package:freezed_annotation/freezed_annotation.dart&#39;;
import &#39;...eatures/profile/domain/entities/user_profile_entity.dart&#39;;

part &#39;user_profile_details_state.freezed.dart&#39;;

@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 &#39;package:freezed_annotation/freezed_annotation.dart&#39;;
import &#39;....features/profile/domain/entities/user_properties_entity.dart&#39;;

part &#39;user_properties_state.freezed.dart&#39;;

@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 &#39;...core/di/dependency_injection.dart&#39;;
import &#39;...core/errors/failures.dart&#39;;
import &#39;...core/presentation/riverpod/check_token_notifier.dart&#39;;
import &#39;...features/profile/presentation/riverpod/user_profile_details_state.dart&#39;;
import &#39;package:riverpod_annotation/riverpod_annotation.dart&#39;;

part &#39;user_profile_details_notifier.g.dart&#39;;

@riverpod
class UserProfileDetailsNotifier extends _$UserProfileDetailsNotifier {
  @override
  UserProfileDetailsState build() {
    getUserProfileDetailsData();
    return const UserProfileDetailsState.initial();
  }

  Future&lt;void&gt; 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 &#39;...core/di/dependency_injection.dart&#39;;
import &#39;...core/errors/failures.dart&#39;;
import &#39;...core/presentation/riverpod/check_token_notifier.dart&#39;;
import &#39;...features/profile/presentation/riverpod/user_properties_state.dart&#39;;
import &#39;package:riverpod_annotation/riverpod_annotation.dart&#39;;

part &#39;user_properties_notifier.g.dart&#39;;

@riverpod
class UserPropertiesNotifier extends _$UserPropertiesNotifier {
  @override
  UserPropertiesState build() {
    getUserPropertiesData();
    return const UserPropertiesState.initial();
  }

  Future&lt;void&gt; 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: () =&gt; null,
  data: (properties) =&gt; userProfileDetails.whenOrNull(
      orElse: () =&gt; null,
      data: (details) =&gt; 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: () =&gt; null,
  data: (properties) =&gt; userProfileDetails.whenOrNull(
      orElse: () =&gt; null,
      data: (details) =&gt; CommonState.data(properties + details),
  ),
);

if (state == null) {
  // same with repeat with error
}

You can use the required fields in whenOrNull, or split into ifs

huangapple
  • 本文由 发表于 2023年5月10日 19:44:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76217985.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定