Skip to content

v1.3.0

Latest

Choose a tag to compare

@abhimuktheeswarar abhimuktheeswarar released this 06 Aug 08:23
· 1 commit to master since this release

Added

ReduceAction — typed, self-reducing actions that fix the lost-update problem.

When multiple SideEffects read a state snapshot, compute a new collection from it,
and dispatch the whole collection as a replacement, the last writer silently
overwrites the others' changes. awaitState() cannot prevent this — it guarantees
a fresh read, not a safe write.

A ReduceAction is a normal, named action that carries only the delta in its
properties and its own reduce(state) merge. It is dispatched like any other
action; the state machine applies reduce against the current state — not the
snapshot the SideEffect saw — so concurrent updates compose instead of overwriting
each other:

data class MergeItemsAction(val entries: Map<String, Int>) : ReduceAction<ItemsState> {
    override fun reduce(state: ItemsState) = state.copy(items = state.items + entries)
}

// In a SideEffect: heavy computation stays here, off the state machine
val delta = heavyProcessing(response)
// Dispatch the operation like any other action; reduce() merges into the CURRENT state
dispatch(MergeItemsAction(delta))

Because it is a regular Action, it stays part of the flow: middleware sees it,
it appears in actions/actionStates with its payload visible in logs, and other
SideEffects can react to it. Keep reduce() fast and pure — carry precomputed
deltas, and combine them with the current state. Works uniformly for maps, lists,
sets, and scalar fields.

See the Concurrency and Collections
wiki page for the full guidance, including list-specific rules (operate by stable
IDs or anchors computed inside reduce(), never by snapshot-derived indexes).

Removed

setState and SetStateAction (introduced in 1.2.0) are removed.

setState solved the same lost-update problem but exposed an anonymous write
path that let code bypass typed actions entirely — against Flywheel's design,
where every state change is a named action in the flow. ReduceAction provides
the same atomicity as part of the action vocabulary.

Migrating from 1.2.0 (if you adopted setState):

// 1.2.0
setState("mergeItems") { copy(items = items + delta) }

// 1.3.0
data class MergeItemsAction(val delta: Map<String, Int>) : ReduceAction<ItemsState> {
    override fun reduce(state: ItemsState) = state.copy(items = state.items + delta)
}
dispatch(MergeItemsAction(delta))

Code coming from 1.1.7 or earlier needs no changes.

Install

Gradle:

implementation("com.msabhi:flywheel:1.3.0")          // Kotlin Multiplatform
implementation("com.msabhi:flywheel-android:1.3.0")  // Android

Swift Package Manager — add https://github.com/abhimuktheeswarar/Flywheel.git
and select 1.3.0.

Full changelog: v1.2.0...v1.3.0