Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Composable is recomposing endlessly after flow collect

My composable is recomposing endlessly after flow collect and navigating to a new screen.
I can’t understand why.

I’m using Firebase for Auth with Email and Password.

I had to put some Log.i to test my function and my composable, and yes, my Main composable (SignUp) is recomposing endlessly after navigating.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

ViewModel

// Firebase auth
private val _signUpState = mutableStateOf<Resources<Any>>(Resources.success(false))
val signUpState: State<Resources<Any>> = _signUpState

fun firebaseSignUp(email: String, password: String) {
    job = viewModelScope.launch(Dispatchers.IO) {
        firebaseAuth.firebaseSignUp(email = email, password = password).collect {
            _signUpState.value = it
            Log.i("balito", "polipop")
        }
    }
}

fun stop() {
    job?.cancel()
}

SignUp

@Composable
fun SignUp(
    navController: NavController,
    signUpViewModel: SignUpViewModel = hiltViewModel()
) {
    val localFocusManager = LocalFocusManager.current
    Log.i("salut", "salut toi")
    Column(
        modifier = Modifier
            .fillMaxSize()
            .systemBarsPadding()
            .padding(16.dp)
            .background(color = PrimaryColor)
    ) {
        BackButton(navController = navController)
        Spacer(modifier = Modifier.height(30.dp))
        Text(
            text = stringResource(id = R.string.sinscrire),
            fontFamily = visby,
            fontWeight = FontWeight.SemiBold,
            fontSize = 28.sp,
            color = Color.White
        )
        Spacer(modifier = Modifier.height(2.dp))
        Text(
            text = stringResource(R.string.prenez_votre_sante_en_main),
            fontFamily = visby,
            fontWeight = FontWeight.SemiBold,
            fontSize = 20.sp,
            color = Grey
        )
        Spacer(modifier = Modifier.height(20.dp))
        Email(signUpViewModel = signUpViewModel, localFocusManager = localFocusManager)
        Spacer(modifier = Modifier.height(16.dp))
        Password(signUpViewModel = signUpViewModel, localFocusManager = localFocusManager)
        Spacer(modifier = Modifier.height(30.dp))
        Button(value = stringResource(R.string.continuer), type = Type.Valid.name) {
            localFocusManager.clearFocus()
            signUpViewModel.firebaseSignUp(signUpViewModel.emailInput.value, signUpViewModel.passwordInput.value)
        }
        Spacer(modifier = Modifier.height(16.dp))
        Button(value = stringResource(R.string.inscription_avec_google), type = Type.Other.name) {

        }
        Spacer(modifier = Modifier.weight(1f))
        Box(
            modifier = Modifier
                .fillMaxWidth(),
            contentAlignment = Alignment.Center
        ) {
            ClickableTextInfo(stringResource(id = R.string.deja_un_compte_se_connecter), onClick = {})
        }
    }
    Response(navController = navController, signUpViewModel = signUpViewModel)
    DisposableEffect(key1 = signUpViewModel.signUpState.value == Resources.success(true)) {
        onDispose {
            signUpViewModel.stop()
            Log.i("fin", "fin")
        }
    }
}

@Composable
private fun Response(
    navController: NavController,
    signUpViewModel: SignUpViewModel
) {
    when (val response = signUpViewModel.signUpState.value) {
        is Resources.Loading<*> -> {
            //WaitingLoaderProgress(loading = true)
        }
        is Resources.Success<*> -> {
            response.data.also {
                Log.i("lolipop", "lolipopi")
                if (it == true) {
                    navController.navigate(Screen.SignUpConfirmation.route)
                }
            }
        }
        is Resources.Failure<*> -> {
//            response.throwable.also {
//                Log.d(TAG, it)
//            }
        }
    }
}

>Solution :

During navigation transition recomposition happens multiple times because of animations, and you call navController.navigate on each recomposition.

You should not cause side effects or change the state directly from the composable builder, because this will be performed on each recomposition, which is not expected in cases like animation.

Instead you should use side effects. In your case, LaunchedEffect should be used.

if (response.data) {
    LaunchedEffect(Unit) {
        Log.i("lolipop", "lolipopi")
        navController.navigate(Screen.SignUpConfirmation.route)
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading