10

I want some clarification on BlocProvider and RepositoryProvider. From official API reference, they provide the same functionality - they provide an instance of an object to its descendant widgets.

However, judging by the names, I guess BlocProvider should be used for Bloc objects only, and RepositoryProvider for everything else. Is this correct?

lordvidex
  • 3,581
  • 3
  • 17
  • 25
Sevastyan Savanyuk
  • 5,797
  • 4
  • 22
  • 34

2 Answers2

6

RepositoryProvider acts like Repository pattern
It's Data Provider provide data to Bloc, so Bloc do not need to know data come from cloud or sqflite or ...
And do merge/filter, see official example below

In the following LoginForm example
Repository is part of Bloc and you can use _userRepository.login

class LoginFormBloc extends FormBloc<String, String> {
      final emailField = TextFieldBloc(validators: [Validators.email]);
      final passwordField = TextFieldBloc();

      final UserRepository _userRepository;

      LoginFormBloc(this._userRepository);

      @override
      List<FieldBloc> get fieldBlocs => [emailField, passwordField];

      @override
      Stream<FormBlocState<String, String>> onSubmitting() async* {
        try {
          _userRepository.login(
            email: emailField.value,
            password: passwordField.value,
          );
          yield currentState.toSuccess();
        } catch (e) {
          yield currentState.toFailure();
        }
      }
    }

You can inject your Repository to Bloc
code snippet

class LoginForm extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<LoginFormBloc>(
      builder: (context) =>
          LoginFormBloc(RepositoryProvider.of<UserRepository>(context)),
      child: Builder(
        builder: (context) {
          final formBloc = BlocProvider.of<LoginFormBloc>(context);

          return Scaffold(
            appBar: AppBar(title: Text('Simple login')),
            body: FormBlocListener<LoginFormBloc, String, String>(
              onSubmitting: (context, state) => LoadingDialog.show(context),
              onSuccess: (context, state) {
                LoadingDialog.hide(context);
                Navigator.of(context).pushReplacementNamed('success');
              },
              onFailure: (context, state) {
                LoadingDialog.hide(context);
                Notifications.showSnackBarWithError(
                    context, state.failureResponse);
              },

you can reference https://flutterawesome.com/create-beautiful-forms-in-flutter/

for official example https://bloclibrary.dev/#/architecture
The bloc layer can depend on one or more repositories to retrieve data needed to build up the application state.

class Repository {
    final DataProviderA dataProviderA;
    final DataProviderB dataProviderB;

    Future<Data> getAllDataThatMeetsRequirements() async {
        final RawDataA dataSetA = await dataProviderA.readData();
        final RawDataB dataSetB = await dataProviderB.readData();

        final Data filteredData = _filterData(dataSetA, dataSetB);
        return filteredData;
    }
}

class BusinessLogicComponent extends Bloc<MyEvent, MyState> {
    final Repository repository;

    Stream mapEventToState(event) async* {
        if (event is AppStarted) {
            try {
                final data = await repository.getAllDataThatMeetsRequirements();
                yield Success(data);
            } catch (error) {
                yield Failure(error);
            }
        }
    }
}
chunhunghan
  • 51,087
  • 5
  • 102
  • 120
-1

Simple Answer

Same as BlocProvider.

BlockProvider provides the bloc to its children through BlockProvider.of(context). In most cases, developers create a new BlocProvider and that gets available to the rest of the subtree.

Now come to RepositoryProvider

RepositoryProvider provides the repository to its children through RepositoryProvider.of(context). When developers create a new RepositoryProvider and that gets available to the rest of the subtree.

Imam T
  • 439
  • 4
  • 6