-
Notifications
You must be signed in to change notification settings - Fork 3
Reducer
Abhi Muktheeswarar edited this page Jul 7, 2021
·
1 revision
typealias Reducer<A, S> = (A, S) -> S
A reducer is a pure function that takes the current State
and an Action
to compute a new State
. In Flywheel, the reducer lives inside StateReserve
.
val reducer = reducerForAction<CounterAction, CounterState> { action, state ->
with(state) {
when (action) {
is CounterAction.IncrementAction -> copy(counter = counter + 1)
is CounterAction.DecrementAction -> copy(counter = counter - 1)
is CounterAction.ResetAction -> copy(counter = 0)
is CounterAction.ForceUpdateAction -> copy(counter = action.count)
else -> state
}
}
}
There can be only one reducer associated with a StateReserve
. However, we can combine multi reducers to create a root reducer.
By having multiple child reducers, we can have a better separation of concerns. Flywheel comes with two helper functions to combine multiple reducers.
fun <S : State> combineReducers(vararg reducers: Reduce<S>): Reduce<S> =
{ action, state ->
reducers.fold(state, { s, reducer ->
reducer(action, s)
})
}
operator fun <S> Reduce<S>.plus(other: Reduce<S>): Reduce<S> = { action, state ->
other(action, this(action, state))
}
Example:
val incrementReducer =
reducerForAction<CounterAction.IncrementAction, CounterState> { _, state ->
with(state) { copy(counter = counter + 1) }
}
val decrementReducer =
reducerForAction<CounterAction.DecrementAction, CounterState> { _, state ->
with(state) { copy(counter = counter - 1) }
}
val resetReducer = reducerForAction<CounterAction.ResetAction, CounterState> { _, state ->
with(state) { copy(counter = 0) }
}
Using combineReducers
val rootReducer = combineReducers(incrementReducer, decrementReducer, resetReducer)
Using plus
val rootReducer = incrementReducer.plus(decrementReducer).plus(resetReducer)
If the number of actions that can update the state is less, you can just stick with one reducer.
- A reducer should be a pure function. It means, reducer should only calculate the new state value based on the current
State
andAction
. - Reducers are not allowed to modify the existing state. Instead, they must make immutable updates, by copying the existing state and making changes to the copied values. (In
Kotlin
data class
helps to achieve this with thecopy
function). - They must not do any asynchronous logic or other "side effects" like sending analytics event or logging something. Doing so, it violates the rules of a pure function.
- Keep your reducers small by making use of
combineReducers
andplus
helper functions. - Ideally, avoid iterating over large collections in a reducer, since it makes other actions to wait for a longer period of time in the queue. A better way to do is to, do the iteration and required updates in a
SideEffect
anddispatch
anAction
likeUpdateMoviesListAction(movies)
to set the updated collections.