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

3

7

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?

Jerryjerrybuild answered 12/2, 2022 at 18:45 Comment(1)
Did you find an answer to that?Paddie
A
5

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.

Alesandrini answered 22/8, 2022 at 3:46 Comment(2)
what if you are using hiltViewModel to directly inject the viewModel at the child composable site. Is this bad practice?Laveralavergne
@Laveralavergne Whether you use HiltViewModel or not, directly injecting a ViewModel into a child Composable can cause problems. It's better to design Composables to accept necessary data or dependencies as inputs to avoid these issues.Alesandrini
O
5

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

Oystercatcher answered 22/8, 2022 at 4:23 Comment(4)
First link is dead.Hieratic
It wasn't dead; there were two slashes placed in one of the 'path nodes".Oystercatcher
what if you are using hiltViewModel to directly inject the viewModel at the child composable site. Is this bad practice?Laveralavergne
Sorry, not familiar with hilt. I'll probably look into it though.Oystercatcher
E
2

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.

Everest answered 28/3, 2023 at 15:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.