Skip to content

Acting across multiple states

Let’s assume we have our state modeled like this:

sealed interface ListState
object Loading : ListState
data class ShowContent : ListState
data class Error (val message : String) : ListState

If for whatever reason you want to trigger a state change for all states you can achieve that by using inState<> on a base class.

// DSL specs
spec {
    inState<ListState> {
        // on, onEnter, collectWhileInState for all states because
        // ListState is the base class, thus these never get cancelled
    }

    inState<Loading> {
        // on, onEnter, collectWhileInState specific to Loading state only
    }

    inState<ShowContent> {
        // on, onEnter, collectWhileInState specific to ShowContent state only
    }

    ...
}

In case you want to trigger state changes from a subset of states you could introduce another level to your state class hierarchy. For example the following would allow you to have a inState<PostLoading> block to share actions between ShowContent and Error:

sealed interface ListState {

    // Shows a loading indicator on screen
    object Loading : ListState

    sealed interface PostLoading : ListState

    // List of items loaded successfully, show it on screen
    data class ShowContent(val items: List<Item>) : PostLoading

    // Error while loading happened
    data class Error(val message: String) : PostLoading
}
// DSL specs
spec {
    inState<PostLoading> {
        // on, onEnter, collectWhileInState for all PostLoading states.
        // It means as long as we are in ShowContent or ErrorState this DSL block
        // is active
    }

    inState<ListState> {
         // on, onEnter, collectWhileInState for all ListState states, so for all states of this state machine.
    }

    inState<Loading> {
        // on, onEnter, collectWhileInState specific to Loading state only
    }

    inState<ShowContent> {
        // on, onEnter, collectWhileInState specific to ShowContent state only
    }
    ...
}