Skip to content

Reducer DSL (recommended)

diklimchuk edited this page Feb 24, 2021 · 1 revision

To simplify writing reducers there's an option to write StateReducer using a dsl.

Syntax

  • Edit state
is MyEvent.One -> {
  state { copy(one = 1) }
}
  • Show effect and command
is MyEvent.One -> {
  effects { +MyEffect.One }
  commands { +MyCommand.One }
}
  • Show multiple effects and commands
is MyEvent.One -> {
  effects { 
    +MyEffect.One 
    +MyEffect.Two
  }
  commands { 
    +MyCommand.One 
    +MyCommand.Two 
  }
}

Features

  • Incremental result state editing You can incrementally change result state:
is MyEvent.One -> {
  state { copy(one = 1) }
  state { copy(two = 2) }
  # Result: State(one = 1, two = 2)
}
  • Access source state and the current state
is MyEvent.One -> {
  # state: State(one = 1, two = 2), initialState: State(one = 1, two = 2)
  state { copy(one = 0) }
  # state: State(one = 0, two = 2), initialState: State(one = 1, two = 2)
  state { copy(one = initialState.one) }
  # state: State(one = 1, two = 2), initialState: State(one = 1, two = 2)
}
  • Edit result in a separate function This allows easier logic reusing
is MyEvent.Five -> {
  applyDiff()
  state { copy(one = 1) }
}

private fun Result.applyDiff() {
  state { copy(one = 0) }
  state { copy(one = initialState.one + 3) }
}

Sample

object BasicDslReducer : DslReducer<MyEvent, MyState, MyEffect, MyCommand>() {

    override fun Result.reduce(event: MyEvent) = when (event) {
        is MyEvent.One -> {
            state { copy(one = 1) }
            state { copy(two = 2) }
        }
        
        is MyEvent.Two -> effects { +MyEffect.One }
        is MyEvent.Three -> commands {
            +MyCommand.Two
            +MyCommand.One
        }
        is MyEvent.Four -> if (event.flag) {
            state { copy(one = 1) }
            commands { +MyCommand.One }
            effects { +MyEffect.One }
        } else {
            state { copy(one = state.two, two = state.one) }
            effects { +MyEffect.One }
        }
        is MyEvent.Five -> applyDiff()
        is MyEvent.Six -> {
            commands { +MyCommand.One.takeIf { event.flag } }
        }
    }

    // Result editing can be done in a separate function
    private fun Result.applyDiff() {
        state { copy(one = 0) }
        state { copy(one = initialState.one + 3) }
    }
}