ajwah_bloc 1.9.0
ajwah_bloc: ^1.9.0 copied to clipboard
Rx based state management library. Manage your application's states, effects, and actions easy way. Make apps more scalable with a unidirectional data-flow.
ajwah_bloc #
Rx based state management library. Manage your application's states, effects, and actions easy way. Make apps more scalable with a unidirectional data-flow.
States
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);
break;
case ActionTypes.Dec:
yield state.copyWith(count: state.count - 1, isLoading: false);
break;
case ActionTypes.AsyncInc:
yield state.copyWith(isLoading: true);
yield await getCount(state.count);
break;
default:
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()]);
//or
createStore(states:[CounterState()], exposeApiGlobally:true);
StreamBuilder<CounterModel>(
stream: select<CounterModel>('counter'),
builder:(context, snapshot) {
if (snapshot.data.isLoading) {
return CircularProgressIndicator();
}
return Text(
snapshot.data.count.toString(),
style: Theme.of(context).textTheme.title,
);
},
)
Action Dispatching
dispatch(Action(type:'Inc'));
Effects #
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$).
Example
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$
.whereType(ActionTypes.AsyncInc)
.debounceTime(Duration(milliseconds: 500))
.mapTo(Action(type: ActionTypes.Inc));
}
List<Stream<Action>> registerEffects(Actions action$, Store store$) {
return [effectForAsyncInc(action$, store$)];
}
}
Api #
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})