Flutter Bloc模式:嵌套API调用在事件处理程序中

发布于 2025-02-04 09:00:10 字数 2431 浏览 4 评论 0原文

我对颤动是相对较新的,并且仍然试图熟悉颤抖的集体图案。我创建了一个authbloc来处理用户身份验证。
验证流量如下:
#1-使用凭据(称为第一个端点)中的用户符号。
#2-签名成功时,我们可以访问用户访问和刷新令牌。
#3-使用检索到的访问令牌获取用户配置文件(第二个端点)。
#4-将用户令牌和用户配置文件保存到身份验证的状态。

在我的authbloc中,我想在收到loginRequested事件时一个接一个地提到的端点。我得到了这个未经治疗的例外:

发射在正常的事件处理程序完成后被调用。 这通常是由于事件处理程序中未知的未来。 请确保与活动处理程序一起等待所有异步操作

任何帮助都非常感谢!

我的代码:

/*auth_event.dart*/
// When the user signing in with login and password this event is called
// and the [AuthRepository] is called to sign in the user
class LoginRequested extends AuthEvent {
  final CredentialsDTO credentials;

  LoginRequested(this.credentials);
}

/*auth_state.dart*/
// When the user is authenticated the state is changed to Authenticated.
class Authenticated extends AuthState {
  final String accessToken;
  final String refreshToken;
  final User? user;

  Authenticated(this.accessToken, this.refreshToken, this.user);
  @override
  List<Object?> get props => [accessToken, refreshToken, user];
}

/*auth_bloc.dart*/
// On login button press, send the LoginRequested Event to the AuthBloc
// to handle it and emit the Authenticated State if the user is authenticated
    on<LoginRequested>((event, emit) async {
      emit(Loading());
      final response = await loginUseCase!.call(
        LoginParams(
          login: CredentialsModel(
            login: event.credentials.login,
            password: event.credentials.password,
          ),
        ),
      );
      response.fold(
        (failure) {
          emit(
              AuthError(ErrorObject.mapFailureToErrorObject(failure: failure)));
          emit(UnAuthenticated());
        },
        // I am having trouble in this section of the code !
        (success) async {
          final accessToken = success.accessToken;
          final refreshToken = success.refreshToken;
          final response = await fetchProfileUseCase!.call(
            FetchProfileParams(
              token: SociaLoginModel(accessToken: accessToken),
            ),
          );
          response.fold(
            (failure) {
              emit(AuthError(
                  ErrorObject.mapFailureToErrorObject(failure: failure)));
              emit(UnAuthenticated());
            },
            (success) async =>
                emit(Authenticated(accessToken, refreshToken, success.user)),
          );
        },
      );
    });

I am relatively new to Flutter and still trying to get familiar with the Flutter Bloc pattern. I have created an AuthBloc to handle user authentication.
The auth flow is as follows :
#1 - user signs in using credentials (first endpoint is called).
#2 - when signing is successful we have access to user access and refresh tokens.
#3 - fetch user profile using the retrieved access token (second endpoint is called).
#4 - user tokens as well as user profile are saved to the authenticated state.

In my AuthBloc I want to call both mentioned endpoints one after the other when I receive a LoginRequested event. I am getting this unhandled exception :

emit was called after an event handler completed normally.
This is usually due to an unawaited future in an event handler.
Please make sure to await all asynchronous operations with event handlers

Any help is very much appreciated !.

My code :

/*auth_event.dart*/
// When the user signing in with login and password this event is called
// and the [AuthRepository] is called to sign in the user
class LoginRequested extends AuthEvent {
  final CredentialsDTO credentials;

  LoginRequested(this.credentials);
}

/*auth_state.dart*/
// When the user is authenticated the state is changed to Authenticated.
class Authenticated extends AuthState {
  final String accessToken;
  final String refreshToken;
  final User? user;

  Authenticated(this.accessToken, this.refreshToken, this.user);
  @override
  List<Object?> get props => [accessToken, refreshToken, user];
}

/*auth_bloc.dart*/
// On login button press, send the LoginRequested Event to the AuthBloc
// to handle it and emit the Authenticated State if the user is authenticated
    on<LoginRequested>((event, emit) async {
      emit(Loading());
      final response = await loginUseCase!.call(
        LoginParams(
          login: CredentialsModel(
            login: event.credentials.login,
            password: event.credentials.password,
          ),
        ),
      );
      response.fold(
        (failure) {
          emit(
              AuthError(ErrorObject.mapFailureToErrorObject(failure: failure)));
          emit(UnAuthenticated());
        },
        // I am having trouble in this section of the code !
        (success) async {
          final accessToken = success.accessToken;
          final refreshToken = success.refreshToken;
          final response = await fetchProfileUseCase!.call(
            FetchProfileParams(
              token: SociaLoginModel(accessToken: accessToken),
            ),
          );
          response.fold(
            (failure) {
              emit(AuthError(
                  ErrorObject.mapFailureToErrorObject(failure: failure)));
              emit(UnAuthenticated());
            },
            (success) async =>
                emit(Authenticated(accessToken, refreshToken, success.user)),
          );
        },
      );
    });

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

尤怨 2025-02-11 09:00:11

所以我设法解决了我的问题。这是我的做法:
我没有直接调用登录事件中的提取物端点,而是重新分配了如下所示的代码。
解决方案是在处理第一个事件之后,将第二个事件添加到集团中,第二个事件Onprofilerequested将单独处理第二个API调用并更新Authstate。

 on<LoginRequested>(
      (event, emit) async {
        emit(Loading());
        final response = await loginUseCase!.call(
          LoginParams(
            login: CredentialsModel(
              login: event.credentials.login,
              password: event.credentials.password,
            ),
          ),
        );
        response.fold(
          (failure) {
            emit(
              AuthError(
                ErrorObject.mapFailureToErrorObject(failure: failure),
              ),
            );
            emit(
              UnAuthenticated(),
            );
          },
          // On successful signin, send the ProfileRequested Event to the AuthBloc
          // to handle it and emit the Authenticated State
          (success) => add(
            ProfileRequested(
              TokenDTO(
                accessToken: success.accessToken,
                refreshToken: success.refreshToken,
              ),
            ),
          ),
        );
      },
    );

on<ProfileRequested>((event, emit) async {
      final accessToken = event.token.accessToken;
      final response = await fetchProfileUseCase!.call(
        FetchProfileParams(
          token: SociaLoginModel(accessToken: accessToken),
        ),
      );
      emit.isDone;
      response.fold((failure) {
        emit(AuthError(ErrorObject.mapFailureToErrorObject(failure: failure)));
        emit(UnAuthenticated());
      }, (success) {
        emit(Authenticated(
            event.token.accessToken, event.token.refreshToken!, success.user));
      });
    });

``

So I managed to solve my issue. Here is how I did it:
Instead of directly calling the fetchProfile endpoint inside the LoginRequested Event, I refactored the code like shown below.
The solution is to add a second event to the bloc after the first one is handled, the second event OnProfileRequested will separately handle the second api call and update the AuthState.

 on<LoginRequested>(
      (event, emit) async {
        emit(Loading());
        final response = await loginUseCase!.call(
          LoginParams(
            login: CredentialsModel(
              login: event.credentials.login,
              password: event.credentials.password,
            ),
          ),
        );
        response.fold(
          (failure) {
            emit(
              AuthError(
                ErrorObject.mapFailureToErrorObject(failure: failure),
              ),
            );
            emit(
              UnAuthenticated(),
            );
          },
          // On successful signin, send the ProfileRequested Event to the AuthBloc
          // to handle it and emit the Authenticated State
          (success) => add(
            ProfileRequested(
              TokenDTO(
                accessToken: success.accessToken,
                refreshToken: success.refreshToken,
              ),
            ),
          ),
        );
      },
    );

on<ProfileRequested>((event, emit) async {
      final accessToken = event.token.accessToken;
      final response = await fetchProfileUseCase!.call(
        FetchProfileParams(
          token: SociaLoginModel(accessToken: accessToken),
        ),
      );
      emit.isDone;
      response.fold((failure) {
        emit(AuthError(ErrorObject.mapFailureToErrorObject(failure: failure)));
        emit(UnAuthenticated());
      }, (success) {
        emit(Authenticated(
            event.token.accessToken, event.token.refreshToken!, success.user));
      });
    });

``
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文