Best practices for building UI with Jetpack Compose per Android Architecture Recommendations. Unidirectional Data Flow (UDF), lifecycle-aware state collection, plain state holders for reusable UI, performance, and theming.
Follow Android Architecture Recommendations (strongly recommended for Compose).
onClick, onValueChange); ViewModel processes them and updates state.viewModel.uiState.collectAsStateWithLifecycle() and pass state down. Never collect flows without lifecycle awareness.Make Composables stateless whenever possible by moving state to the caller.
@Composable
fun MyComponent(
value: String, // State flows down
onValueChange: (String) -> Unit, // Events flow up
modifier: Modifier = Modifier
)
collectAsStateWithLifecycle() when collecting StateFlow from ViewModel.
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
collectAsState() or collect without lifecycle handling.modifier: Modifier = Modifier as the first optional parameter.modifier to the root layout element of your Composable.padding().clickable() is different from clickable().padding(). Generally apply layout-affecting modifiers (like padding) after click listeners if you want the padding to be clickable.remember: Use remember { ... } to cache expensive calculations across recompositions.derivedStateOf: Use derivedStateOf { ... } when a state changes frequently (like scroll position) but the UI only needs to react to a threshold or summary (e.g., show "Jump to Top" button). This prevents unnecessary recompositions.
val showButton by remember {
derivedStateOf { listState.firstVisibleItemIndex > 0 }
}
viewModel::onEvent) or remembered lambdas to prevent unstable types from triggering recomposition of children.MaterialTheme.colorScheme and MaterialTheme.typography instead of hardcoded colors or text styles.DesignSystem.kt or Components.kt) if they are shared across features.@Preview(showBackground = true) and include Light/Dark mode previews if applicable.