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.
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)
// }
}
}
}
CodePudding user response:
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)
}
}