mvflow / net.pedroloureiro.mvflow / Handler

Handler

typealias Handler<State, Action, Mutation> = (State, Action) -> Flow<Mutation> (source)

Handler is a function that receives the current state and an action that just happened and acts on it.

It returns a kotlinx.coroutines.flow.Flow of Mutation which is the way it can mutate the current state if it needs to.

Note: implementations should return straight away and do any operations inside the flow.

Keep also in mind that Mutations should indicate how to change the state, but should not rely on/assume what the current state is (as of when the action was emitted).

// Good example: it returns a Flow immediately

val good: Handler<State, Action, Mutation> = { _, _ ->
    flow {
        slowOperation1()
        emit(Mutation.A)
        slowOperation2()
        emit(Mutation.B)
    }
}

// Bad example: doing something slow before returning flow

val bad: Handler<State, Action, Mutation> = { _, _ ->
    slowOperation1()
    flow {
        emit(Mutation.A)
        slowOperation2()
        emit(Mutation.B)
    }
}
// How to create good mutations:

data class State(val counter: Int)
sealed class Mutation {
    data class Add(val amount: Int)
    // The next mutation is a bad example, don't use it
    data class SetValue(val newValue: Int)
}

// Good example - explain how to modify the state

val good: Handler<State, Action, Mutation> = { _, _ ->
    // simulate long work
    delay(1_000)
    emit(Mutation.Add(1))
}
// [good] always works. Even if 3 actions are emitted quickly, each one will emit an adition of 1 and the
// reducer will work properly

// Bad example - don't assume that state is still up to date. That is the reducer's job.

val bad: Handler<State, Action, Mutation> = { state, _ ->
    // simulate long work
    delay(1_000)
    emit(Mutation.SetValue(state.counter+1))
}

// [bad] has a bug. If several actions are emitted in less than a second (the time it takes to do the long
// operation in this example), when each of these actions complete, it will emit a mutation to set the
// value to initial state + 1, overriding the changes of the previous actions that meanwhile had changed the
// current state.