Jetpack Compose: Thinking in Composables

Compose replaces XML layouts with declarative Kotlin code. The mental model shift is the hardest part.

Key Insights

  • Composables are functions, not objects — think transformation, not mutation
  • State hoisting separates what to display from how to manage state
  • remember and rememberSaveable handle different lifecycle scopes

State Hoisting Pattern

@Composable
fun CounterScreen() {
    var count by remember { mutableStateOf(0) }
    Counter(count = count, onIncrement = { count++ })
}

@Composable
fun Counter(count: Int, onIncrement: () -> Unit) {
    Column {
        Text("Count: $count")
        Button(onClick = onIncrement) { Text("Increment") }
    }
}

Side Effects

@Composable
fun UserScreen(userId: String) {
    var user by remember { mutableStateOf<User?>(null) }

    LaunchedEffect(userId) {
        user = api.fetchUser(userId)
    }

    user?.let { UserCard(it) }
}

Lists with LazyColumn

LazyColumn {
    items(users, key = { it.id }) { user ->
        UserRow(user)
    }
}

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.