0

How can i fetch value from a state and use it in a function in bloc?

I have this events

on<AddUserEmailEvent>((getUserEmail)); // gets value from textfield on onchanged
on<AddUserPassWordEvent>((getUserPassWord)); // gets value from textfield on onchanged


// get email function
      void getUserEmail(AddUserEmailEvent event, Emitter<SignUpState> emit) {
        debugPrint("email ${event.email}"); // im getting value here.
        emit(AddUserEmailState(event.email)); // is this the correct method?
      }

on triggering these event im able to get the values from the ui and into the bloc. My question is, is this the correct method to get the form data from ui into the bloc? If it is how can i use the values that are passed in to the state to the function say

on<OnClickedSignUpEvent>(_signUp());

where the _signUp function would be expecting email and password?

Future<dynamic> _signUp(String userMail, String password){ 
debugPrint("emai $userMail  passWord $password");
}

I'm new to bloc. if this is not the correct method what would be the correct method?

Febin Johnson
  • 277
  • 1
  • 6
  • 21

1 Answers1

1

The event handlers in Bloc have the following signature:

FutureOr<void> Function(BlocEvent e, Emitter<BlocState> emit) { ... }

Where BlocEvent and BlocState are the base types for your Bloc's events and states respectively.

Your events should contain the data that is required to handle the event, and your handler can then use the event's data to perform some action (i.e. signUp). Afterwards, you should emit some new state depending on what happened (maybe the sign up failed, etc.).

Example:

First, let's define our event classes (see code comments):

/// The base class for our Bloc's events.
abstract class UserEvent {
  const UserEvent();
}

/// The event that is dispatched when the user taps the sign-up button.
class UserSignUpEvent extends UserEvent {
  const UserSignUpEvent({
    required this.email,
    required this.password,
  });

  final String email;
  final String password;
}

Alright, now whenever the user taps the sign-up button, we can dispatch a UserSignUpEvent to our Bloc, which will handle the actual implementation (this separates/decouples the sign-up logic from the UI logic).

Next, let's define the states that our Bloc can emit in response to the UserSignUpEvent:

/// The base class for our Bloc's states.
///
/// It is non-abstract for simplicity and in order to use it as the initial
/// state.
///
/// However, it might be clearer (depending on your needs), to have an
/// intermediate UserSignUpPending state; I'll leave this up to you.
class UserState {
  const UserState();
}

/// State emitted when the user sign-up fails.
class UserSignUpFailure extends UserState {
  const UserSignUpFailure({required this.error});

  /// The reason why the sign-up failed; likely returned by the API.
  final Object error;

  /// See [UserSignUpSuccess.operator==] for an explanation.
  @override
  bool operator==(Object other) {
    return identical(this, other) ||
        other is UserSignUpFailure && other.error == error;
  }

  /// See [UserSignUpSuccess.hashCode] for an explanation.
  @override
  int get hashCode => error.hashCode;
}

/// State emitted when the user sign-up is successful.
///
/// The contained [username] and [token] are likely returned by the API.
class UserSignUpSuccess extends UserState {
  const UserSignUpSuccess({required this.username, required this.token});

  final String username;
  final String token;
  // ... other data returned by your API, that you need in your application ...

  /// State should implement equality, so that if the same state is emitted by
  /// the Bloc, the UI is not unneccessarily rebuilt.
  @override
  bool operator==(Object other) {
    return identical(this, other) ||
        other is UserSignUpSuccess &&
            other.username == username &&
            other.token == token;
  }

  /// If you implement `==`, you should also implement `hashCode`.
  @override
  int get hashCode => Object.hash(username, token);
}

Now that we have defined our events and states, let's implement the actual Bloc:

/// The [UserBloc] responds to [UserEvent]s and emits [UserState]s.
class UserBloc extends Bloc<UserEvent, UserState> {
  /// We pass the repository to the Bloc's constructor, so that we can make
  /// API calls as needed.
  UserBloc({required this.repository}) : super(const UserState()) {
    on<UserSignUpEvent>(_onUserSignUp);
  }

  /// API repository.
  final UserRepository repository;

  /// The concrete event type is passed, and the generic emitter is passed.
  void _onUserSignUp(UserSignUpEvent event, Emitter<UserState> emit) async {
    try {
      /// We call the [UserRepository.signUp] method, which signs the user up.
      /// 
      /// For demonstrative purposes, it also returns a token.
      final token = await repository.signUp(event.email, event.password);

      /// Validate data here, if needed.

      /// At this point, the data was validated and the user is signed up.
      /// 
      /// Let's emit the [UserSignUpSuccess] state.
      /// 
      /// Note that we pass the username from the event, but the token from
      /// the API response.
      emit(UserSignUpSuccess(username: event.email, token: token));
    } catch (e) {
      /// Oh no, some error occurred, let's emit the error state.
      /// 
      /// Our application should handle this state and display an error to the
      /// user (SnackBar, Dialog, etc.) by using a [BlocListener] on the UI.
      emit(UserSignUpFailure(error: e));
    }
  }
}

The UserRepository class is a simple mock interface:

class UserRepository {
  Future<String> signUp(String username, String password) async {
    /// Perform the actual sign-up API call here.
    await Future.delayed(const Duration(seconds: 1));

    /// Process the response here.
    /// ...
    /// Return the processed data.
    return "my API token";
  }
}

From your UI (your sign-up widget), you can then simply call:

context.read<UserBloc>().add(
            UserSignUpEvent(
              username: _usernameTextEditingController.text,
              password: _passwordTextEditingController.text,
            ),
          );

You should be able to hook up that last part.


The Bloc docs are very extensive, and I recommend reading their examples for more complete coverage.

Link: https://bloclibrary.dev/#/gettingstarted

offworldwelcome
  • 1,314
  • 5
  • 11