mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 18:39:55 +02:00
Added a comprehensive collection of Compose development guidelines, best practices, and skill definitions in the .codex directory. Co-authored-by: Junie <junie@jetbrains.com>
5.0 KiB
5.0 KiB
Navigation
Shared navigation concepts for Nav 2 and Nav 3. Load first, then see version-specific references.
References:
Nav 2 vs Nav 3 Decision Guide
| Criterion | Nav 3 (NavDisplay) | Nav 2 (NavHost / NavController) |
|---|---|---|
| Back stack ownership | You own it (SnapshotStateList) |
Library owns it (NavController) |
| Navigation model | List manipulation — add(), removeLastOrNull() |
Imperative — navigate(), popBackStack() |
| MVI alignment | Natural — back stack is state you mutate | Requires bridging — controller calls in effect handlers |
| Deep link parsing | You parse URIs, construct back stack manually | Built-in NavDeepLink parsing |
| Scenes / adaptive layouts | First-class: dialog, bottom sheet, list-detail | Manual: separate composable overlays |
| CMP support | Full (Android, iOS, Desktop, Web) | Android-only (JetBrains forks exist but differ) |
| Maturity | Newer — verify artifact stability for production | Stable, battle-tested |
| Fragment interop | None | Full Fragment/Activity integration |
When to use Nav 3:
- New Compose projects following MVI architecture
- Compose Multiplatform projects targeting multiple platforms
- Projects wanting direct back stack control as state
- Projects needing adaptive layout scenes (list-detail, dialog, bottom sheet)
When to use Nav 2:
- Existing codebases already built on
NavHost/NavController - Projects requiring built-in deep link parsing via
NavDeepLink - Hybrid Compose + Fragment apps where Nav 2 provides Fragment integration
- Teams that prefer the declarative
NavGraphDSL
Navigation in MVI
The architectural rule: ViewModels emit semantic effects; the route layer handles navigation. This rule applies identically to both Nav 2 and Nav 3.
sealed interface ItemEffect {
data object NavigateBack : ItemEffect
data class OpenDetails(val id: String) : ItemEffect
}
// Nav 3 route layer — manipulates back stack
CollectEffect(viewModel.effect) { effect ->
when (effect) {
is ItemEffect.NavigateBack -> backStack.removeLastOrNull()
is ItemEffect.OpenDetails -> backStack.add(Details(effect.id))
}
}
// Nav 2 route layer — calls NavController
CollectEffect(viewModel.effect) { effect ->
when (effect) {
is ItemEffect.NavigateBack -> navController.navigateUp()
is ItemEffect.OpenDetails -> navController.navigate(Detail(effect.id))
}
}
Rules
- Never call navigation during composition — always in
LaunchedEffector event handler callbacks - Never pass the back stack (Nav 3) or
NavController(Nav 2) to the ViewModel or leaf composables - ViewModel emits semantic effects (
NavigateBack,OpenDetails(id)) - Route/navigation layer translates effects to navigation calls
- Keep navigation logic at the route boundary, not in screens or leaves
Anti-Patterns
| Anti-pattern | Applies to | Why it hurts | Better replacement |
|---|---|---|---|
| Navigating during composition | Both | Triggers on every recomposition, causes infinite loops | Navigate in LaunchedEffect or event handler callbacks |
| Passing NavController/back stack to ViewModel | Both | Violates MVI boundary, navigation becomes business logic | ViewModel emits semantic effects; route handles navigation |
| String-based routes without type safety | Both | No compile-time checking, argument mismatch at runtime | @Serializable data classes/objects |
Missing onBack handler |
Nav 3 | System back gesture does nothing | Always provide onBack = { backStack.removeLastOrNull() } |
| Globally-scoped ViewModel for per-screen data | Both | Data leaks across screens, not cleared on pop | Entry-scoped VMs (Nav 3 decorators) or destination-scoped VMs (Nav 2) |
| Recreating back stacks on tab switch | Both | Loses user navigation history within tabs | Persistent per-tab stacks (Nav 3) or saveState/restoreState (Nav 2) |
| Missing entry decorators | Nav 3 | ViewModels leak, saveable state lost | Always include both rememberSaveableStateHolderNavEntryDecorator and rememberViewModelStoreNavEntryDecorator |
| Using Nav 2 in new MVI codebases | Nav 3 preferred | Nav 3's user-owned back stack aligns better with MVI state ownership | Prefer Nav 3 NavDisplay for new MVI-first projects; Nav 2 remains valid for existing codebases |
Version-Specific References
Load the file that matches your task:
- Nav 3 routes, tabs, scenes, deep links, or back stack patterns → navigation-3.md
- Nav 2 NavHost, tabs, deep links, nested graphs, or animations → navigation-2.md
- Wiring Hilt or Koin with Nav 3 → navigation-3-di.md
- Wiring Hilt or Koin with Nav 2 → navigation-2-di.md
- Migrating from Nav 2 to Nav 3 → navigation-migration.md