Describe state hoisting and its benefits in Compose

Understanding unidirectional data flow in declarative UI.
Move state to the caller, pass value and event lambda down, keep them stateless.
Internal state in reusable composables or calling hoisting boilerplate.
WHAT THIS TESTS: This question probes whether you understand the core Compose principle that state should live at the appropriate level of the UI tree and that composables should ideally be stateless functions of data. Interviewers want to see that you can separate state ownership from state display, which directly impacts testability, reusability, and unidirectional data flow.
A GOOD ANSWER COVERS: First, a crisp definition: state hoisting means moving the state and the logic that mutates it out of the composable and up to its caller. The composable then accepts the current value as a parameter and an event lambda such as onValueChange or onCheckedChange. Second, the why: by making the composable stateless, you gain reusability because the same UI piece can be dropped into different screens with different state sources. Third, testability improves dramatically because you can call the composable in a unit test or preview with simple parameters instead of mocking a ViewModel or Compose runtime. Fourth, you should mention that the caller now owns the single source of truth, which prevents bugs from split state and aligns with declarative UI patterns.
COMMON WRONG ANSWERS: Keeping remember or rememberSaveable inside a supposedly reusable component and arguing it is simpler. Suggesting that only ViewModel state needs hoisting while internal UI state can stay anywhere. Claiming hoisting creates too much boilerplate without acknowledging the trade-offs. Confusing state hoisting with lifting state into a ViewModel specifically; hoisting is about caller ownership, which could be a parent composable, a screen-level state holder, or a ViewModel.
LIKELY FOLLOW-UPS: Where should you stop hoisting? The answer is the common ancestor that needs to read or mutate the state, or a screen-level state holder if multiple unrelated composables need it. How does this relate to Compose performance? Stateless composables skip recomposition more predictably when inputs do not change. What about inputs like TextField? You should still hoist the text value even if it feels verbose, because it lets you react to changes, validate input, or drive derived state.
ONE CONCRETE EXAMPLE: Imagine a custom Toggle composable. A non-hoisted version uses remember { mutableStateOf(false) } internally. A hoisted version accepts isOn: Boolean and onToggle: () -> Unit. The parent owns the boolean, perhaps in a ViewModel or in another composable using remember. Now Toggle can be used in a settings screen, a dialog, or a list item without change. In a screenshot test or preview, you pass true or false directly and tap the lambda to assert behavior.
Source: developer.android.com
Read the original → developer.android.com
- #android
- #jetpack-compose
- #state-hoisting
- #ui-architecture
- #declarative-ui
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.