What is preferable... to pass the full uiState as ...
# compose
p
What is preferable... to pass the full uiState as a parameter to a composable that requires various uiState parameters? or to pass all the parameters separatedly from the uiState? The second option makes my call very huge, and if I need to call the same composable multiple times (for example for different orientations), it makes it tedious. Sample in thread.
Copy code
RouteMapPanel(
            simpleMapCenterLocation = uiState.simpleMapCenterLocation,
            selectedLocation = uiState.selectedLocation,
            selectedLocationAddress = uiState.selectedLocationAddress,
            originLocation = uiState.originLocation,
            destinationLocation = uiState.destinationLocation,
            hasLocationPermission = uiState.hasLocationPermission,
            updateSimpleMapCenterLocation = { vm.updateSimpleMapCenterLocation(it) },
            updateSelectedLocation = { vm.updateSelectedLocation(it) },
            onOriginSelected = {
                vm.updateSelectedLocation(null)
                vm.transformLatLngIntoAddress(it, AddressType.ORIGIN)
            },
            onDestinationSelected = {
                vm.updateSelectedLocation(null)
                vm.transformLatLngIntoAddress(it, AddressType.DESTINATION)
            },
            onNavigate = { vm.navigate(context) },
            onSwitchAddresses = { vm.switchAddresses() }
        )
m
What i'll normally do is to layer the function so that there's a raw version that just takes all the values and callbacks, and then a layer that takes the ui state and/or view model and breaks that down into the call to the raw function.
I think it results in a nice clear separation of concerns between view (composable) and model (ui state / vm)
p
I don't catch you, can you show it?
also, passing down a vm seems to be a bad practice
m
Copy code
data class UIState(
    val name: String
)

@Composable
fun MyScreen(uiState: UIState) {
    Text(uiState.name)
}

@Composable
fun MyScreen(name: String) {
    Text(name)
}
do the first function takes the uiState and breaks it down so that you can call the lower level functions which takes the properties as individual things. This idea extends to callbacks and things like that as well. Obviously a view model can be used in the same way.
Here's a bit more complete example that involves a VM. You'll just have to figure out how you're getting a hold of your factory
Copy code
data class UIState(
    val name: String
)

class MyVM: ViewModel() {
    var uiState by mutableStateOf( UIState("") )
    fun onClick() {

    }
}

@Composable
fun MyScreen(vmFactory: ViewModelProvider.Factory) {
    val vm: MyVM = viewModel(factory = vmFactory)
    MyScreen(vm)
}


@Composable
fun MyScreen(myVM: MyVM) {
    MyScreen(myVM.uiState.name, onClick = myVM::onClick)
}

@Composable
fun MyScreen(name: String, onClick: () -> Unit) {
    Button(onClick = onClick) {
        Text(name)
    }
}
But the general idea is make each layer have a single responsibility. In this case, you have • View • VM Decomposition • VM Creation
p
sorry but I don't see why this is better than simply passing down the event's and the parameters, I only can see you are adding more code with no reason
for sure there is a point that I'm not understanding
m
The advantage is layering and single responsibility. You can test each responsibility on it's own. It makes for a clear separation of concerns. Again nothing is forcing you into this, you asked for opinions, and I gave you mine. Others might have different approaches, but this is the approach that myself and my entire team agreed to adopt when building our screens.