Dominik Seemayr
Dominik Seemayr

Reputation: 889

Is it bad practice to pass viewmodels to child composables in jetpack compose?

Example:

I have a @Composable func WorkoutScreen(...) which injects a dedicated ViewModel (e.g. with hilt). It displays some different child composables like @Composable func ProgressView(...) and some others. ProgressView is the only composable in the whole screen, which observes/needs a specific State property x from the injected ViewModel. Would it be bad practice to pass the ViewModel from WorkoutScreen as parameter down to ProgressView? Or should I just pass the States value only?

Let's think this further and say I pass only the State. Also let's say, not ProgressView is the one needing the State, but just another child of ProgressView. If the State changes now, the whole ProgressView might be recompositioned since "its input changes" (instead of just the child), if I understood correctly. Wouldn't this lead to unnecessary recomps?

Upvotes: 7

Views: 4661

Answers (3)

Panagiotis Tzelalis
Panagiotis Tzelalis

Reputation: 41

Pass ViewModel to child composables is a BAD practice. You have to pass only values and callbacks that you need to avoid unnecessary recompositions and make your composables more reusable.
Also, using hiltViewModel will create a ViewModel instance base to NavGraph destination and not the specific composable you will call it.

Upvotes: 2

Richard Onslow Roper
Richard Onslow Roper

Reputation: 6835

The entire Composable shouldn't recompose, since Compose is efficient enough to recompose only the Composable which are explicitly reading a state.

Don't worry about efficiency, it won't get affected. For the principles part, no, you shouldn't pass the model around. That is because of the separation-of-concerns principle. All the parts of the program should have access to only as much information as they need to function - no more, no less.

If you pass the entire viewmodel around, firstly every part of the app will have access to everything inside the viewmodel, and may modify properties leading to conflicts. It also makes the viewmodel tightly coupled with a lot of Composable code, whereas passing only the state, limits the coupling to only the part of the viewmodel that is actually required by the Composable. Finally y, if you pass the viewmodel around, it would be practically impossible to test your apps, since you'll need to generate a whole new "fake" viewmodel, with fake values for testi, which will become problematic as the model grows more and complex.

Use state-hoisting. Read here: https://developer.android.com/codelabs/jetpack-compose-state#8, or another stack overflow answer

Upvotes: 7

Android poet
Android poet

Reputation: 71

Passing a ViewModel to a child composable is not very good practice. Only Screen-Level Composables (Main UI Page) should access ViewModel business logic. There are two main benefits of this approach:

  1. Your child's composable will become reusable.

  2. There is no concrete implementation, So you can easily update the

    business logic.

Upvotes: 7

Related Questions