Compose Best Practices

Best practices for writing Jetpack Compose UI in Archery Apprentice.


State Hoisting

// GOOD: State hoisted to ViewModel
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
    val state by viewModel.uiState.collectAsState()
 
    MyContent(
        items = state.items,
        onItemClick = { viewModel.onItemClicked(it) }
    )
}
 
@Composable
private fun MyContent(
    items: List<Item>,
    onItemClick: (Item) -> Unit
) {
    // Stateless component
}

Remember and rememberSaveable

// Remember across recompositions
val scrollState = rememberScrollState()
 
// Survive configuration changes
var text by rememberSaveable { mutableStateOf("") }

Derived State

@Composable
fun MyScreen() {
    val items by viewModel.items.collectAsState()
 
    // Derive state - only recomputes when items change
    val sortedItems = remember(items) {
        items.sortedBy { it.name }
    }
}

LaunchedEffect

@Composable
fun MyScreen(itemId: Long) {
    LaunchedEffect(itemId) {
        viewModel.loadItem(itemId)
    }
}

Performance Tips

  1. Use key() in lists for stable identity
  2. Avoid creating lambdas in loops
  3. Use Modifier efficiently
  4. Hoist state when possible
  5. Use remember for expensive calculations


Last Updated: 2025-11-01