SelectorFor

Single Field Selector

SelectorFor allows to select specific fields in a object and trigger a callback when those fields change (by reference or by value).

SelectorFor is used together with BlocSelector , to choose the data from a Bloc state that we want to use as state that should trigger recomposition.

More precisely, with SelectorFor we can build an AbstractSelector object that we can pass as argument to BlocSelector. Let's see some examples on how this is done.

Let us assume that the state object from which we want to select data is the following:

class StateABC(val a:Int, val b:Int, val c:Int)

For example if we are interested in the a field, we can write:

//sel_a is of type AbstractSelector<StateABC>
val sel_a = SelectorFor<StateABC>.withSingleField { a }

Selector for Multiple Fields

With a selector we can also check for changes of multiple fields in an object and combine them in a computed value:

//sel_sum_ab is of type AbstractSelector<StateABC>
val sel_sum_ab =
 SelectorFor<StateABC>
    .withField{a}
    .withField{b}
    .compute {a,b -> a+b}

sel_sum_ab will keep track when the class field a and b change and automatically recompute their sum and trigger a state change with the value of the sum.

Equality Check by Reference or by Value

Let's say now that we the following state object:

data class StateABCStrings(val astr:String="", val bstr:String="", val cstr:String="")

Again, if we are interested in the a field, we can write

//sel_astr  is of type AbstractSelector<StateABCStrings>
val sel_astr = SelectorFor<StateABCStrings>.withSingleField { astr }

But what happens when the state change? The selector sel_astr we have built is able to identify changes to the astr field. By default changes are checked by reference . In other words if we have the two states:

val state1 = StateABCStrings(astr="aa")
val state2 = StateAbcStrings.copy(astr="a"+a")

the two states state1 and state2 are considered different by the selector sel_astr . This is not always the desired behaviour. Sometimes we want to check if the "value", not the "reference" of a field has changed. If this is what we want then we must use withSingleFieldByValue

//sel_astr_by_val  is of type AbstractSelector<StateABCStrings>
val sel_astr_by_val = SelectorFor<StateABCStrings>.withSingleFieldByValue { astr }

With this definition of the selector state1 and state2 above will be considered equal and will not considered a state change.

We can choose equality check by value also for selectors based on multiple fields:

//sel_sum_ab_str  is of type AbstractSelector<StateABCStrings>
val sel_sum_ab_str =
 SelectorFor<StateABCStrings>
    .withFieldByValue{ astr }
    .withFieldByValue{ bstr }
    .compute {astr, bstr  -> astr+bstr }

Building multiple selectors for the same state

SelectorFor is can be used to build multiple AbstractSelector at once, as we can see in the following example:

val sel = SelectorFor<StateABC>

val sel_a = sel.withSingleField { a } //this is an AbstractSelector<StateABC>
val sel_b = sel.withSingleField { b } //this is an AbstractSelector<StateABC>
val sel_for_a = sel.withField { a } //this is still a BUILDER for an AbstractSelector
val sel_sum_ab = sel_for_a.withField { b }.compute {a,b->a+b} //this is an AbstractSelector<StateABC>
val sel_sum_ac = sel_for_a.withField { c }.compute {a,c->a+c}  //this is an AbstractSelector<StateABC>

Last updated