DEV Community

myougaTheAxo
myougaTheAxo

Posted on • Originally published at zenn.dev

Advanced State Management in Compose - MVI, Reducer & Side Effects

Advanced State Management in Compose

MVI Pattern

sealed class UserIntent {
    object Load : UserIntent()
    data class UpdateName(val name: String) : UserIntent()
}

data class UserState(
    val name: String = "",
    val isLoading: Boolean = false,
    val error: String? = null
)

fun reducer(state: UserState, intent: UserIntent): UserState = when (intent) {
    UserIntent.Load -> state.copy(isLoading = true)
    is UserIntent.UpdateName -> state.copy(name = intent.name)
}
Enter fullscreen mode Exit fullscreen mode

Reducer Pure Function

@Composable
fun UserScreen() {
    var state by remember { mutableStateOf(UserState()) }

    fun dispatch(intent: UserIntent) {
        state = reducer(state, intent)
    }

    dispatch(UserIntent.Load)
}
Enter fullscreen mode Exit fullscreen mode

Channel for One-Shot UiEffect

val effectChannel = Channel<UiEffect>(Channel.BUFFERED)

LaunchedEffect(Unit) {
    for (effect in effectChannel) {
        when (effect) {
            is UiEffect.ShowToast -> showToast(effect.message)
            is UiEffect.Navigate -> navigate(effect.route)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

State Splitting for Recomposition Optimization

@Composable
fun OptimizedScreen() {
    val listState by viewModel.listState.collectAsState()
    val headerState by viewModel.headerState.collectAsState()

    Column {
        // HeaderState recomposes only when headerState changes
        Header(headerState)

        // ListState recomposes independently
        List(listState.items)
    }
}
Enter fullscreen mode Exit fullscreen mode

8 Android app templates on Gumroad

Top comments (0)