Observers
The SSP segments the state into 3 reactive parts, the state value (state), the error object (error), and the state loading action (loading).
These segments are observed in a listener or separate listeners. They can also be combined to obtain a new segment, always starting from the 3 main segments.
#
ObserversWe can observe the segments separately or together by using store.observer();
//Observer all segmentsvar _dispose = counter.observer( onState: (state) => print(state),//called when the state changes onError: (error) => print(error),//called when the error changes onLoading: (loading) => print(loading),//called when the loading changes);
_dispose(); //cancel the observer
On Widgets we can observe on a Builder with ScopedBuilder or observe all changes with TripleBuilder.
#
DisposeThe observer returns a function that can be called to cancel the observation.
#
DistinctBy default, the Store's observer does not react to repeated objects. This behavior is beneficial as it avoids state reconstructions and notifications if the segment has not been changed.
It is good practice to overwrite the operation== of the state value and error. A good tip is also to use the package equatable to simplify this type of comparison.
#
SelectorsWe can recover the reactivity of the segments individually for transformations or combinations. We have then 3 selectors that can be retrieved as Store properties: store.selectState, store.selectError and store.selectLoading.
The type of selectors changes depending on the reactive tool you are using in the Stores. For example, if you are using StreamStore then your selectors will be Streams, however, if you are using NotifierStore then your selectors will be ValueListenable;
RxValueListenable<int> myState$ = counter.selectState;RxValueListenable<dynamic> myError$ = counter.selectError;RxValueListenable<bool> myLoading$ = counter.selectLoading;
#
ListenersThe listeners are used to listen to the segments and react to them. They are called when there is any change in the segments.
#
TripleListenerUse TripleListener to listen all segment modifications and reflect them in the listener callback.
Exemple:
//Observer all segmentsTripleListener( store: counter,//the store to be observed listener: (context, triple) => print(triple.state),//called when any segment changes child: Container(), //the child to be built),
#
ScopedListenerUse ScopedListener to listen all segment modifications and reflect them in the recpective segment listener callbacks.
Exemple:
//Observer all segmentsScopedListener( store: counter,//the store to be observed onState: (context, state) => print(state),//called when the state changes onError: (context, error) => print(error.toString()),//called when the error changes onLoading: (context, isLoading) => print(isLoading),//called when the loading changes child: Container()//the child to be built),
#
BuildersThe builders are used to listen to the segments and react to them. They are called when there is any change in the segments.
#
ScopedBuilderUse ScopedBuilder to listen the segments, likewise the method store.observer();
//Observer all segmentsScopedBuilder( store: counter,//the store to be observed onState: (context, state) => Text('$state'),//called when the state changes onError: (context, error) => Text(error.toString()),//called when the error changes onLoading: (context) => CircularProgressIndicator(),//called when the loading changes);
#
ScopedBuilder.transitionUse it for adding a custom transition on state change:
//Observer all segmentsScopedBuilder.transition( store: counter,//the store to be observed transition: (_, child) {//called when the state changes return AnimatedSwitcher(//add a custom transition duration: Duration(milliseconds: 400), child: child,//the child to be built ); }, onLoading: (_) => Text('Loading...'),//called when the loading changes onState: (_, state) => Text('$state'),//called when the state changes ),
#
TripleBuilderUse TripleBuilder to listen all segment modifications and reflect them in the Widgets tree.
//Observer all segmentsTripleBuilder( store: counter,//the store to be observed builder: (context, triple) => Text('${triple.state}'),//called when any segment changes);
NOTE: The TripleBuilder builder is called when there is any change in the segments. Its use is recommended only if you are interested in listening to all segments at the same time.
#
ConsumerThe consumer is used to listen to the segments and react to them. They are called when there is any change in the segments.
#
TripleConsumerUse TripleConsumer to listen all segment modifications and reflect them in the Widgets tree and listener callback.
Exemple:
//Observer all segmentsTripleConsumer( store: counter,//the store to be observed listener: (context, triple) => print(triple.state),//called when any segment changes builder: (context, triple) => Text('${triple.state}'),//called when any segment changes),
#
ScopedConsumerUse ScopedConsumer to listen all segment modifications and reflect them in the recpective segment Widgets tree and listener callbacks.
Exemple:
//Observer all segmentsScopedConsumer( store: counter,//the store to be observed onStateListener: (context, state) => print(state),//called when the state changes onErrorListener: (context, error) => print(error.toString()),//called when the error changes onLoadingListener: (context, isLoading) => print(isLoading),//called when the loading changes onState: (context, state) => Text('${triple.state}'),//called when the state changes onError: (context, error) => Text('${triple.state}',//called when the error changes onLoading: (context, isLoading) => Text('${triple.state}',//called when the loading changes),
NOTE: On ScopedBuilder the onLoading is only called on "true". This means that if the state is modified or an error is added, the widget to be built will be the onState or onError. However, it is very important to change Loading to "false" when the loading action is completed. observers of Triple DO NOT PROPAGATE REPEATED OBJECTS (more on this in the section distinct). This behavior is exclusive to ScopedBuilder.