fix state emissions becoming out of sync when using async handlers
This commit is contained in:
parent
72fa795d38
commit
e753cd30ad
|
@ -11,7 +11,6 @@ import app.dapk.state.Store
|
|||
import app.dapk.state.createStore
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class StateViewModel<S, E>(
|
||||
reducerFactory: ReducerFactory<S>,
|
||||
|
@ -32,7 +31,7 @@ class StateViewModel<S, E>(
|
|||
}
|
||||
|
||||
override fun dispatch(action: Action) {
|
||||
viewModelScope.launch { store.dispatch(action) }
|
||||
store.dispatch(action)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,18 +4,26 @@ import kotlinx.coroutines.CoroutineScope
|
|||
import kotlinx.coroutines.launch
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
fun <S> createStore(reducerFactory: ReducerFactory<S>, coroutineScope: CoroutineScope): Store<S> {
|
||||
fun <S> createStore(reducerFactory: ReducerFactory<S>, coroutineScope: CoroutineScope, log: Boolean = false): Store<S> {
|
||||
val subscribers = mutableListOf<(S) -> Unit>()
|
||||
var state: S = reducerFactory.initialState()
|
||||
return object : Store<S> {
|
||||
private val scope = createScope(coroutineScope, this)
|
||||
private val reducer = reducerFactory.create(scope)
|
||||
|
||||
override suspend fun dispatch(action: Action) {
|
||||
scope.coroutineScope.launch {
|
||||
override fun dispatch(action: Action) {
|
||||
coroutineScope.launch {
|
||||
if (log) println("??? dispatch $action")
|
||||
state = reducer.reduce(action).also { nextState ->
|
||||
if (nextState != state) {
|
||||
if (log) {
|
||||
println("??? action: $action result...")
|
||||
println("??? current: $state")
|
||||
println("??? next: $nextState")
|
||||
}
|
||||
subscribers.forEach { it.invoke(nextState) }
|
||||
} else {
|
||||
if (log) println("??? action: $action skipped, no change")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +43,7 @@ interface ReducerFactory<S> {
|
|||
}
|
||||
|
||||
fun interface Reducer<S> {
|
||||
suspend fun reduce(action: Action): S
|
||||
fun reduce(action: Action): S
|
||||
}
|
||||
|
||||
private fun <S> createScope(coroutineScope: CoroutineScope, store: Store<S>) = object : ReducerScope<S> {
|
||||
|
@ -45,7 +53,7 @@ private fun <S> createScope(coroutineScope: CoroutineScope, store: Store<S>) = o
|
|||
}
|
||||
|
||||
interface Store<S> {
|
||||
suspend fun dispatch(action: Action)
|
||||
fun dispatch(action: Action)
|
||||
fun getState(): S
|
||||
fun subscribe(subscriber: (S) -> Unit)
|
||||
}
|
||||
|
@ -82,14 +90,18 @@ fun <S> createReducer(
|
|||
actionHandlers.fold(acc) { acc, handler ->
|
||||
when (handler) {
|
||||
is ActionHandler.Async -> {
|
||||
scope.coroutineScope.launch {
|
||||
handler.handler.invoke(scope, action)
|
||||
}
|
||||
acc
|
||||
}
|
||||
|
||||
is ActionHandler.Sync -> handler.handler.invoke(action, acc)
|
||||
is ActionHandler.Delegate -> when (val next = handler.handler.invoke(scope, action)) {
|
||||
is ActionHandler.Async -> {
|
||||
scope.coroutineScope.launch {
|
||||
next.handler.invoke(scope, action)
|
||||
}
|
||||
acc
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ class ReducerTestScope<S, E>(
|
|||
}
|
||||
private val reducer: Reducer<S> = reducerFactory.create(reducerScope)
|
||||
|
||||
override suspend fun reduce(action: Action) = reducer.reduce(action).also {
|
||||
override fun reduce(action: Action) = reducer.reduce(action).also {
|
||||
capturedResult = it
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue