bloc_lite_flutter 0.2.0

pub package

A Flutter library aimed at making it simple to use the BLoC design pattern to separate the presentation code from the business logic and the state.

This library is built to be used in conjunction with bloc_lite.

API Reference #

Examples #

Glossary #

  • An InheritedBloc is an inherited widget that uses dependency injection to insert a bloc into the widget tree. This bloc can then later be retrieved by calling InheritedBloc.of<BlocTypeHere>(context) on any widget that is a descendent of this widget.
  • An InheritedBlocTree is a widget that allows a convenient way to insert multiple InheritedBlocs into the widget tree without bloating the UI code.
  • A BlocBuilder is a widget that registers a bloc and reactively rebuilds its widget tree whenever that bloc triggers an update. This is the primary way to use blocs in Flutter using this library.
  • A BlocWidget is an abstract widget that user-defined widgets can extend from. It manages a bloc's lifetime events and automatically subscribes to its updates.

Usage #

We can use the counter example from the bloc_lite docs to build a simple counter app in Flutter. (See above for a complete working example of a counter app using several methodologies.)

class CounterBloc extends BlocController {
    int value = 0;

    void increment() {
        value += 1;
        publishUpdate();
    }

    void decrement() {
        value -= 1;
        publishUpdate();
    }
}

To use this bloc in a widget, you can simply create the controller in your widget class and pass it to a BlocBuilder:

class CounterWidget extends StatefulWidget {
    @override
    CounterWidgetState createState() => CounterWidgetState();
}

class CounterWidgetState extends State<CounterWidget> {
    final controller = CounterBloc();

    @override
    dispose() {
        controller.dispose();
        super.dispose();
    }

    @override
    Widget build(BuildContext context) {
        return BlocBuilder(
            controller: controller,
            builder: (BuildContext context, CounterBloc bloc)
                => Center(
                    child: Text(bloc.value.toString()),
                ),
        );
    }
}

Whenever controller publishes an update (for example, by elsewhere in the app calling the increment or decrement function), the BlocBuilder will automatically refresh its widget tree. (Note that the widget class extends StatefulWidget and within the state the dispose method is overriden to call controller.dispose(). This is important as the controller must be disposed in order to close the underlying stream and free up its resources.)

Declaring the bloc in the same class as the widget that uses it is fine for widgets that utilize a local controller and state, but for global controllers and states, you need to be able to access a bloc further down the widget tree from where it was created. This is where InheritedBloc comes in:

class ParentWidget extends StatefulWidget {
    @override
    ParentWidgetState createState() => ParentWidgetState();
}

class ParentWidgetState extends State<ParentWidget> {
    final controller = CounterBloc();

    @override
    dispose() {
        controller.dispose();
        super.dispose();
    }

    @override
    Widget build(BuildContext context) {
        return InheritedBloc(
            bloc: controller,
            child: ChildWidget(),
        );
    }
}

class ChildWidget extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
        final controller = InheritedBloc.of<CounterBloc>(context);
        return BlocBuilder(
            controller: controller,
            builder: (BuildContext context, CounterBloc bloc)
                => Center(
                    child: Text(bloc.value.toString()),
                ),
        );
    }
}

(Note that, although the parent widget extends StatefulWidget in order to properly dispose of the controller, the child widget does not need to and can safely extend StatelessWidget.)

In the previous example, ChildWidget uses InheritedBloc.of to get a reference to the inherited bloc. When the bloc is going to be used as the controller of a BlocBuilder, this is not necessary, as those classes expose a convenient inherited<BlocType> factory constructor for that purpose:

class ChildWidget extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
        return BlocBuilder<CounterBloc>.inherited(
            context: context,
            builder: (BuildContext context, CounterBloc bloc)
                => Center(
                    child: Text(bloc.value.toString()),
                ),
        );
    }
}

In that example, the inherited bloc is automatically inferred from the corresponding InheritedBloc, eliminating the need to explicitly obtain it.

Sometimes you may find yourself injecting multiple blocs at once into the widget tree. To do this, you can nest multiple InheritedBlocs, but that can quickly bloat the widget tree:

Widget build(BuildContext context) {
    return InheritedBloc(
        bloc: controllerA,
        child: InheritedBloc(
            bloc: controllerB,
            child: InheritedBloc(
                bloc: controllerC,
                child: InheritedBloc(
                    ...
                ),
            ),
        ),
    );
}

Instead, you can use an InheritedBlocTree to insert many blocs into the tree at once in an organized and concise fashion:

Widget build(BuildContext context) {
    return InheritedBlocTree(
        blocs: [
            InheritedBloc(bloc: controllerA),
            InheritedBloc(bloc: controllerB),
            InheritedBloc(bloc: controllerC),
            ...
        ],
        child: ...
    )
}

Any blocs injected into the tree in this manner can be retrieved using the same InheritedBloc.of approach as before.

In situations where you are using a bloc controller as a simple correspondence with a widget, you can extend the widget's class with BlocWidget. This abstract class offers a convenient way to associate a controller with a widget as well as automatically manage its lifecycle and subscribe to updates:

class CounterWidget extends BlocWidget<CounterBloc> {
    @override
    CounterBloc createController(BuildContext context) => CounterBloc();

    @override
    Widget build(BuildContext context) {
        return Center(
           child: Text(controller.value.toString()),
       );
    }
}

As you can see, this method offers a much more concise way to use a bloc controller than BlocBuilder or InheritedBloc. The controller is still added to the widget tree in the usual fashion, so widgets further down the widget tree can still access the controller with InheritedBloc.of. The controller is also automatically disposed of when the widget is removed from the widget tree and marked for disposal.

Todo #

  • Add testing suite
  • CodeMagic integration for automated testing and deployment

[0.2.0]

  • Removed [BlocStateWidget] in correspondence with the removal of [BlocState] from the core library. (See that changelog for reasoning.)
  • Renamed [BlocWidget] to [BlocBuilder] for clarity on the purpose of the widget.
  • Added autoDispose field to [BlocBuilder] and [InheritedBloc] that, if true, facilitates the disposal of controller when the widgets themselves are disposed. (True by default, false by default on [BlocBuilder.inherited].)
  • [InheritedBloc] now extends [StatefulWidget] in order to support automatic bloc disposal. (An internal class that extends [InheritedWidget] has been added to maintain compatibility with Flutter-standard dependency injection procedures and to keep the performance of [InheritedBloc.of] unchanged.)
  • Added [BlocWidget] as an abstract class that extends [StatefulWidget]. The purpose of the class is to enable conciseness in associating a bloc controller with a user-defined widget that extends [BlocWidget].

[0.1.1]

  • Updated bloc_lite dependency to 0.1.2
  • Added a more complete README

[0.1.0]

  • Initial release.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  bloc_lite_flutter: ^0.2.0

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:bloc_lite_flutter/bloc_lite_flutter.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
44
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
80
Overall:
Weighted score of the above. [more]
68
Learn more about scoring.

We analyzed this package on Jul 17, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.4.0
  • pana: 0.12.19
  • Flutter: 1.7.8+hotfix.3

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health suggestions

Format lib/src/bloc_builder.dart.

Run flutter format to format lib/src/bloc_builder.dart.

Format lib/src/bloc_widget.dart.

Run flutter format to format lib/src/bloc_widget.dart.

Format lib/src/inherited_bloc.dart.

Run flutter format to format lib/src/inherited_bloc.dart.

Maintenance issues and suggestions

Support latest dependencies. (-10 points)

The version constraint in pubspec.yaml does not support the latest published versions for 1 dependency (bloc_lite).

Maintain an example. (-10 points)

Create a short demo in the example/ directory to show how to use this package.

Common filename patterns include main.dart, example.dart, and bloc_lite_flutter.dart. Packages with multiple examples should provide example/README.md.

For more information see the pub package layout conventions.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.2.2 <3.0.0
bloc_lite ^0.1.2 0.1.3 0.2.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11
meta 1.1.6 1.1.7
rxdart 0.22.0
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test

Admin