$npx -y skills add hanamizuki/solopreneur --skill compose-uiBest practices for building UI with Jetpack Compose, focusing on state hoisting, detailed performance optimizations, and theming. Use this when writing or refactoring Composable functions.
| 1 | # Jetpack Compose Best Practices |
| 2 | |
| 3 | ## Instructions |
| 4 | |
| 5 | Follow these guidelines to create performant, reusable, and testable Composables. |
| 6 | |
| 7 | ### 1. State Hoisting (Unidirectional Data Flow) |
| 8 | Make Composables **stateless** whenever possible by moving state to the caller. |
| 9 | |
| 10 | * **Pattern**: Function signature should usually look like: |
| 11 | ```kotlin |
| 12 | @Composable |
| 13 | fun MyComponent( |
| 14 | value: String, // State flows down |
| 15 | onValueChange: (String) -> Unit, // Events flow up |
| 16 | modifier: Modifier = Modifier // Standard modifier parameter |
| 17 | ) |
| 18 | ``` |
| 19 | * **Benefit**: Decouples the UI from simple state storage, making it easier to preview and test. |
| 20 | * **ViewModel Integration**: The screen-level Composable retrieves state from the ViewModel (`viewModel.uiState.collectAsStateWithLifecycle()`) and passes it down. |
| 21 | |
| 22 | ### 2. Modifiers |
| 23 | * **Default Parameter**: Always provide a `modifier: Modifier = Modifier` as the first optional parameter. |
| 24 | * **Application**: Apply this `modifier` to the *root* layout element of your Composable. |
| 25 | * **Ordering matters**: `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. |
| 26 | |
| 27 | ### 3. Performance Optimization |
| 28 | * **`remember`**: Use `remember { ... }` to cache expensive calculations across recompositions. |
| 29 | * **`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. |
| 30 | ```kotlin |
| 31 | val showButton by remember { |
| 32 | derivedStateOf { listState.firstVisibleItemIndex > 0 } |
| 33 | } |
| 34 | ``` |
| 35 | * **Lambda Stability**: Prefer method references (e.g., `viewModel::onEvent`) or remembered lambdas to prevent unstable types from triggering recomposition of children. |
| 36 | |
| 37 | ### 4. Theming and Resources |
| 38 | * Use `MaterialTheme.colorScheme` and `MaterialTheme.typography` instead of hardcoded colors or text styles. |
| 39 | * Organize simple UI components into specific files (e.g., `DesignSystem.kt` or `Components.kt`) if they are shared across features. |
| 40 | |
| 41 | ### 5. Previews |
| 42 | * Create a private preview function for every public Composable. |
| 43 | * Use `@Preview(showBackground = true)` and include Light/Dark mode previews if applicable. |
| 44 | * Pass dummy data (static) to the stateless Composable for the preview. |