fritz2 icon indicating copy to clipboard operation
fritz2 copied to clipboard

Reconsider `RootStore` update behavior

Open haukesomm opened this issue 11 months ago • 4 comments

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

val allowedCharacters = "abc".toCharArray().toSet()

val sanitizingLens: Lens<String, String> = lensOf(
    format = { it },
    parse = { it.filter { c -> c in allowedCharacters } }
)

val store = storeOf("").map(sanitizingLens)

div("space-y-4") {
    input {
        type("text")
    }.changes.values() handledBy store.update

    p {
        store.data.renderText(into = this)
    }
}

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

haukesomm avatar Mar 21 '24 10:03 haukesomm