Rx based state management library. Manage your application's states, effects, and actions easy way. Make apps more scalable with a unidirectional data-flow.


Every state class must derived from StateBase<T> class. The StateBase<T> class has an abstract function mapActionToState(T state, Action action, Store store). This method should be invoked whenever any action dispatched to the store. You should return a new state based on the action.

import 'package:ajwah_bloc/ajwah_bloc.dart';
import 'package:ajwah_block_examples/actionTypes.dart';

class CounterModel {
  final int count;
  final bool isLoading;
  CounterModel({this.count, this.isLoading});
  CounterModel.init() : this(count: 10, isLoading: false);
  CounterModel copyWith({int count, bool isLoading}) => CounterModel(
      count: count ?? this.count, isLoading: isLoading ?? this.isLoading);

class CounterState extends StateBase<CounterModel> {
  CounterState() : super(name: 'counter', initialState: CounterModel.init());

  Stream<CounterModel> mapActionToState(
      CounterModel state, Action action, Store store) async* {
    switch (action.type) {
      case ActionTypes.Inc:
        yield state.copyWith(count: state.count + 1, isLoading: false);
      case ActionTypes.Dec:
        yield state.copyWith(count: state.count - 1, isLoading: false);
      case ActionTypes.AsyncInc:
        yield state.copyWith(isLoading: true);
        yield await getCount(state.count);
        yield getState(store);

  Future<CounterModel> getCount(int count) {
    return Future.delayed(Duration(milliseconds: 500),
        () => CounterModel(count: count + 1, isLoading: false));

Using state in components

Declare your store as a global variable or enable exposeApiGlobally:true.

var store = createStore(states:[CounterState()]);
createStore(states:[CounterState()], exposeApiGlobally:true);
    stream: select<CounterModel>('counter'),
    builder:(context, snapshot) {
        if (snapshot.data.isLoading) {
          return CircularProgressIndicator();
        return Text(
            style: Theme.of(context).textTheme.title,

Action Dispatching



Every effect class must derived from EffectBase class. And it is optional to pass the effectKey. But it's mandatory if you want conditionally remove the effects by using removeEffectsByKey('effectKey'). The EffectBase class has an abstract method registerEffects(Actions action$, Store store$).


import 'package:ajwah_bloc/ajwah_bloc.dart';
import 'package:rxdart/rxdart.dart';
import '../../actionTypes.dart';

class CounterEffect extends EffectBase {

  CounterEffect() : super(effectKey: "counter-effects");

  Stream<Action> effectForAsyncInc(Actions action$, Store store$) {
    return action$
        .debounceTime(Duration(milliseconds: 500))
        .mapTo(Action(type: ActionTypes.Inc));

  List<Stream<Action>> registerEffects(Actions action$, Store store$) {
    return [effectForAsyncInc(action$, store$)];


dispatch(String actionType, [dynamic payload])
Stream<T> select<T>(String stateName)
Stream<T> selectMany<T>(T callback(Map<String, dynamic> state))
addState(BaseState stateInstance)
removeStateByStateName(String stateName)
addEffects(BaseEffect effectInstance)
removeEffectsByKey(String effectKey)
Stream<List<dynamic>> exportState()
importState(Map<String, dynamic> state)
addEffect(EffectCallback callback, {String effectKey})