When creating forms I find myself doing this a lot...
# compose
c
When creating forms I find myself doing this a lot
Copy code
MyTextField(
    text = vm.state.email,
    onTextChange = vm::emailChange,
...
}
but then
emailChange(text: String)
basically does nothing except for setting the value. Better off just doing
Copy code
MyTextField(
    text = vm.state.email,
    onTextChange = {vm.state.email = it},
I've always "thought" that all logic that can be moved up to a VM should be moved out of the UI layer, but after reading the arch docs im kinda convinced that whether or not i put stuff in a composable or a VM that's both the UI layer, and it basically "doesn't matter" where I put this stuff. Anyway. Thoughts?
l
If this was Java, my first intinct would be ‘What if I want to add some other logic to vm::emailChange in the future’, but since Kotlin supports delegates/custom getter and setter, I don’t see as much reason to create a separate function for it.
f
keep in mind that if you are creating a lambda for the
onTextChange
instead of passing the viewmodel reference, you could be triggering recomposition each time
it is also a matter of separation of concerns. The view should not be concerned with what happens when the text changes, it should just forward that to the viewmodel. You are now moving part of the logic from the viewmodel, where it belongs, to the view. The
state
should only be updated by the viewmodel, now you have 2 entities (the viewmodel and the view) updating it separately
👍🏻 1
if your viewmodel does not need to be told when the text updates, but just needs to get the final value when the user taps a button for instance, then you could move this logic to a State Holder and pass the final value to the button's
onClick
. This assumes the viewmodel does not want to do any validation on the value as it is updated and only wants the final value, but for an email field, I would presume you want to do some validation as it's been typed
You could also do some validation in your state holder, so depends on what your needs are, but I would definitely not update the state in the composable
n
keep in mind that if you are creating a lambda for the
onTextChange
instead of passing the viewmodel reference, you could be triggering recomposition each time
@Francesc could you explain this? Thanks.
f
composables check their arguments for a change and that is used as an optimization to determine if a recomposition is needed or not. By creating a new lambda each time the arguments are different and can trigger a recomposition. I can't say 100% for certain, I would need to run a sample, but based on how compose works, I would expect it to recompose each time
👍 1
👍🏻 1
this is handled by the compose compiler, by the way, happens behind the scenes
n
By creating a new lambda each time the arguments are different and can trigger a recomposition
I think that we have to investigate this deeper, in practice 😉 I have read in the Compose Internals book (although I don't understand it fully yet 😄 ) that the Compose compiler performs very clever optimizations regarding lambdas, even in case of capturing-lambdas. (If the lambda is non-capturing then the Kotlin compiler itself optimizes it into a singleton.) In the book the 'Compose lambda memoization' chapter describes more thoroughly how the Compose compiler replaces simple lambdas with
remember()
and synthetic function calls. It seems to be very smart, so it is best to try before saying that recomposition will happen in a given case...
f
so it is best to try before saying that recomposition will happen in a given case
right, and that's why I prefaced my comment with
could
and noted I was not 100% sure - there are optimizations behind the hood
👍🏻 1