# compose


02/25/2022, 3:13 AM
I am implementing a barcode scanner in Compose. Once it scans a barcode, it needs to do a network request to find the respective item. If an item is found I dismiss the scanner. If it is not found or some error happens, a dialog is shown. In order to accomplish that I think that I will need to do something along these lines:
Copy code
data class DialogState(val isShown: Boolean = false, val message: String = "")

fun Screen(navController: NavController, viewModel: MyViewModel) {
    val dialogState by rememberUpdateState(DialogState)
    val scope = rememberCoroutineScope()
    Button(onClick = { scope.launch { 
        when (val result = viewModel.doRequest()) {
           is Success -> navController.popBackStack()
           is NotFound -> dialogState = DialogState(true, "Not Found")
           else -> dialogState = DialogState(true, "error")
   if (dialogState.isShown) {
Would this be correct ?

Eric Chee

02/25/2022, 3:34 AM
You more or less got the right idea. One suggestion though. i’m gonna assume your viewModel.doRequest() is a suspend function since you wrapped it in a coroutinescope. I would recommend NOT to expose public suspendable functions in your ViewModel to your view. Instead I would recommend using a regular function in the viewmodel and in the implementation of ViewModel, the function uses viewModelScope. And from there you can expose a flow/livedata/rxstream/MutableState for the Composable to observe. Psuedo code
Copy code
class ViewModel {
    val resultFlow: StateFLow<Result>
    fun doRequest() { viewmodelScope.launch{ 
        val result = somerequest()
        resultFlow.value = result
Copy code
fun ...() {
    val result viewModel.resultFLowObserveAsState()
    when (result) {
☝🏻 1
Therefore you wont need a scope for your Composable function, and your view is now free to fire as many requests as needed to the viewmodel, while not worrying about the behind the scenes of how your ViewModel fetches data, async or not
and if you get an error, you can wrap your call in a runCatching{} block and expose a Failed state in either a separate error flow, or through a sealed class in your main viewmodel state flow

Zach Klippenstein (he/him) [MOD]

03/03/2022, 4:05 AM
looks a bit suspicious - are you passing it a companion object? It's definitely not a parameter, which is basically all that function is intended for


03/05/2022, 2:21 AM
@Zach Klippenstein (he/him) [MOD] It has a typo. Pease read it as
Copy code
val dialogState by rememberUpdateState(DialogState())
The initial state is a new
object created with default values for the params