Open haukesomm opened 3 months ago
This needs carefully investigation in order to keep the current and long time established behaviour stable. I am in favor of some flag or somehow "store"-overloading / variant / behaviour approach right now. On the other hand besides "legacy" code we want to support users with our framework to write idiomatic code. That would mean that the current behaviour should rather be treated and branded as deprecated, which in dead would mean some API change.
In an internal meeting @Lysander suggested to change the default behavior of the RootStore
class and filter out identical values on the rendering level instead.
This way the stores would always update but identical contents would not be rendered multiple times.
Another use case that is currently unnecassary hard to solve with the store behaviour:
Imagine some "trigger", that should start some process on any new impulse. The naive but rational approach would look like this:
val trigger = storeOf(Unit)
// some UI that should reacts to the trigger
// below the trigger element
button {
clicks handledBy trigger.update // the "new" Unit gets swallowed :-/
}
To overcome the false "distinctUntilChanged" logic of the store, you could rely on the emittingHandler
-concept:
val trigger = storeOf(Unit).handleAndEmit<Unit, Unit> { _, _ -> emit(Unit) }
Looks complicated and cumbersome imho!
Current insights:
MutableStateFlow
which is internally used by RootStore
implicitly filters out equal valkues. So the above example relies on this behaviour.SubStore
) has an explicit call to distinctUntilChanged
, which was initially imposed to avoid unnecassary renderings of portions of complex data models.We would need to change both code places therefore.
Current behavior
Currently, a
RootStore
's value is only updated (i.e.data
flow emits a new value) if the Store receives a new value. If the Store receives a value that is equal to the current value, no value is emitted.This is due to the fact that a
MutableStateFlow
is used to keep track of the current value which is explicitly designed to behave this way.Why this is problematic
Imagine a
Lens
that is used to strip illegal characters from an input (e.g. characters from a phone number). The expected behavior would be like this:1) Add invalid characters to an input field with a valid input 2) Invalid characters get stripped by the Lens 3) The store is updated 4) The formatting Lens passes the sanitized value upstream to the input 5) The input field is updated to have the sanitized value
Instead, the following happens:
1) Add invalid characters to an input field with a valid input 2) Invalid characters get stripped by the Lens 3) The store is not updated since the sanitized input is the same as the current value 4) Nothing is passed upstream 5) The input field keeps the illegal input
Example code
Proposal
Consider one of the following options:
1) Introduce a flag to explictly update the Store's data on any new input 2) Change the Store's default behavior to always emit a new value, regardless of the equality of the input