Not every state holder is a ViewModel
Compose has two kinds of state holder: plain classes that live in the composition, and ViewModels that outlive it. Knowing which to reach for is what keeps UiState classes from growing to twenty fields.
7 posts
Compose has two kinds of state holder: plain classes that live in the composition, and ViewModels that outlive it. Knowing which to reach for is what keeps UiState classes from growing to twenty fields.
Compose's recommended architecture is three layers with one-directional dependencies. The split inside the UI layer — elements and state holders — is the one that decides whether a screen can be tested without a device.
CompositionLocal passes values down the composition without parameters. That invisibility is the feature and the danger: three tests for when it is the right tool, and what to use instead when it isn't.
Correct hoisting can still produce an unmaintainable codebase. The four failure modes that show up once a screen grows past a few components, and the fixes for each.
Hoisting to a ViewModel is a different decision from hoisting to a parent composable. The dividing question is lifetime, and getting it wrong in either direction has a specific cost.
State hoisting means moving state to the lowest common ancestor of everything that needs it. The trigger is a second reader — not a rule to apply preemptively.
In Views you fix UI by reaching in and mutating it. Compose removes that ability entirely. Understanding why the removal is the feature is what makes the rest of Compose make sense.