Composable 在流收集后不断重组

Composable is recomposing endlessly after flow collect

我的可组合项在流收集并导航到新屏幕后不断地重新组合。 我不明白为什么。

我使用 Firebase 通过电子邮件和密码进行身份验证。

我不得不放置一些 Log.i 来测试我的功能和我的可组合项,是的,我的主要可组合项 (SignUp) 在导航后不断地重新组合。

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()
}

注册

@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)
//            }
        }
    }
}

在导航转换过程中,由于动画会发生多次重组,并且您在每次重组时调用 navController.navigate

您不应导致副作用或直接从可组合构建器更改状态,因为这将在每次重组时执行,这在动画等情况下是不可预料的。

您应该使用 side effects. In your case, LaunchedEffect 应该使用。

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