Trying to work with ViewModel and Compose, I’m not...
# compose
a
Trying to work with ViewModel and Compose, I’m not sure which one would be the preferred approach. Anyone have opinions on this? I’m worried the first one is inefficient, unless Compose somehow only recomposes the updated value (such as username)
a
the first option is ok. and there is no big difference between these two options in terms of performance. and yes, the function will be recomposed only when the input value like username has been changed
a
Thanks for the quick response! By no big difference do you mean they behave/compose the same way or diff is negligible? Worried because I’ll be building a screen with more components, not just two text fields.
l
Put your state on top of your composables but related to them. That says, in your example I would put
username
state into
Screen
function. You should break down your composables into smaller ones at your own discretion. Regarding the question about putting state in ViewModel or composable function...I have a question: @Andrey Kulikov Does
remember
or
by state
survive a configuration change. If not, I would put state in
ViewModel
if it has to survive configuration changes otherwise in composables.
a
there are separate analogues functions
rememberSavedInstanceState
and
savedInstanceState
that behaves as
remember
and
state
, but also survives the configuration change/process recreation
a
Thank you both for your help!
l
@allan.conda In your second example, there are some differences between the two worth considering: When you mutate the username state object, its going to recompose the scopes where it was read. In the top case (declared as deep as possible), that means that just the lambda surrounding the TextField will recompose, so this is pretty efficient. In the bottom case, It will recompose
Top
, which will then call Screen, which will then call some other things and eventually TextField. You can see how in this example the top one is going to be the more efficient of the two, but it also means that the
username
state can’t be used in very many places (just the scope where you defined it). In a way, that’s not an accident. This is why we generally say to define the state as deep as possible, which is to say, the deepest common ancestor of all of the places in the tree that actually need to read it. I also might say that the best advice might be just to write it in a way that “feels good”. That is, declare the username variable in a place where it feels natural to declare it. For me, that would probably be at the top of the Screen composable, but not in the Top composable, even though the version you posted was more efficient, putting the variables at the top fo the function is generally what feels right to me. And I do so not for performance reasons, but just for readability etc.
One of Compose’s philosophies is that we try really hard to make the code that you would write “naturally” be code that performs relatively well, so that you don’t have to think about this all of the time
👍 3
A lot of these concepts are new, so it makes sense to ask these questions. In kotlin, there are all kinds of interesting tidbits about code patterns that perform slightly better than something else thats equivalent, but I find that most people will just write the code that feels the most natural and its “good enough” most of the time. We want Compose to be the same way. If you want to learn these differences you certainly can, and in some cases it might really matter, but we want to make it so that in most cases it does not.
l
Thanks for elaborating. This is also interesting to me
a
Thank you! It verified a lot of my assumptions. I definitely want to learn the difference because everyone in my team will be asking me the same question when I introduce this to them 🙂 and now I have an answer. I was specially concerned of pairing Compose with ViewModels since all the state will basically be at the top-level and no one wants the whole screen to be re-rendered for a small property change unless someone says it doesn’t matter performance-wise. @Leland Richardson [G] does your advice still apply for this case? Like I said I’m specially worried about building more complex screens.
s
Seconding everything Leland said. Don't worry about it and optimize the special case is definitely the way to go here. In practical compose usage the position state is owned has never been a thing I've had to optimize – though sometimes you do need to be careful about reading the state (e.g. in an animation based layout).
When thinking about ViewModels, it's it's worth pointing out that state that changes together recomposes together. So if you have a few observables from a ViewModel that update only when the data they hold should change, that's gonna be fine. If you pass all of the values for your entire UI through a flat immutable data class the entire state object will trigger recomposition whenever any fields change.
That said, recomposition is pretty cheap and data updates tend to happen fairly rarely, so it'll be performant enough most of the time.