Looking for advice on form state management with d...
# compose-desktop
l
Looking for advice on form state management with domain
data class
objects updated by the inputs. To use or not to use? Details will be in the thread.
Copy code
class UserFormViewModel {
    val userRepository = UserRepository()

    var userData: UserData? by mutableStateOf(null)
}


@Composable
fun userForm(
    modifier: Modifier = Modifier,
) {
    val vm = remember { UserFormViewModel() }

    onActive {
        MainScope().launch {
            vm.userData = vm.userRepository.createNew()
        }
    }

    Column(
        modifier = modifier.padding(16.dp)
            .border(BorderStroke(2.dp, Color.LightGray)),
    ) {
        formRow(above = { Text("First Name: ") }) {
            TextField(
                value = vm.userData?.firstName ?: "",
                onValueChange = { vm.userData = vm.userData?.copy(firstName = it) }
            )
        }

        formRow(above = { Text("Last Name: ") }) {
            TextField(
                value = vm.userData?.lastName ?: "",
                onValueChange = { vm.userData = vm.userData?.copy(lastName = it) }
            )
        }

        formRow {
            Button(
                onClick = {
                    MainScope().launch {
                        vm.userData?.let { vm.userRepository.update(it) }
                    }
                }
            ) {
                Text("Save")
            }
        }
    }
}
This implementation recomposes all fields that rely on
userData
. I would prefer this to not happen. I know I can break it out into individual fields in the
UserFormViewModel
class but then would need to manually create the userData class for repository use. Is there a method to use a data class without having to replace the object on input like the above?
Secondly (I'm still learning coroutines) I would like to store
MainScope()
in a variable, but I am unsure if this would cause weird behavior. My gut tells me that I shouldn't do something like
val scope = remember { MainScope() }
but I don't have a solid reason why and I have not yet seen an example of it being used in that way.
k
Is this specific to desktop>
l
It is.
It's just a learning project for me
Kotlin et al.
x
What is the goal of having the coroutine scope in a val?
l
From the docs of
MainScope()
an example is given:
Copy code
lass MyAndroidActivity {
    private val scope = MainScope()

    override fun onDestroy() {
        super.onDestroy()
        scope.cancel()
    }
}
presumably to save having to call it every time. I'm open to correction
Granted that's in Android, and perhaps the same principle doesn't apply. From what I can gather
MainScope()
is intended to be used in UI settings.
x
Well this is I think to kill the "demon" couroutine thread and prevent it from running after the Main process is killed
depends if that's what you want to happen
I do not do such thing since I am fine having an file export run even if the user exits the application
However while writing this - I might be dead wrong keeping such thing alive. In case the demon goes into an infite loop. But I have to admit I am not sure if the demon has some kind of time to live and therefore will be killed anyway after some time after the main app has been killed
l
Thinking through this again, I think you're right.
1