Composable点击按钮不重组:登录页SnackBar仅首次生效
问题分析与解决方案
问题根源
你的SnackBar仅首次触发有效,核心原因是shouldShowSnackBar状态的更新逻辑有缺陷:
- 首次点击按钮时,
shouldShowSnackBar从false变为true,触发LaunchEffect执行并显示SnackBar。 - 但SnackBar显示完毕后,
shouldShowSnackBar依然保持true,后续再次点击按钮时,即使用户名/密码仍为空,该状态值没有发生变化,导致LaunchEffect的key未更新,因此不会再次触发SnackBar。
修复方案1:重置状态变量
在LaunchEffect中,SnackBar显示完成后手动将shouldShowSnackBar重置为false,确保下次点击按钮时状态能再次从false变为true,触发LaunchEffect:
@Composable fun Login() { var username by remember { mutableStateOf("") } var password by remember { mutableStateOf("") } val scaffoldState = rememberScaffoldState() var shouldShowSnackBar by remember { mutableStateOf(false) } println("LoginScreen") LaunchedEffect(key1 = shouldShowSnackBar) { if (shouldShowSnackBar) { println("ShouldShowSnackBar") scaffoldState.snackbarHostState.showSnackbar( message = "Please enter a username and password", duration = SnackbarDuration.Short ) // SnackBar显示完成后重置状态 shouldShowSnackBar = false } } Scaffold(scaffoldState = scaffoldState) { Column(modifier = Modifier.fillMaxWidth()) { OutlinedTextField( label = { Text(text = "Username") }, value = username, onValueChange = { username = it } ) OutlinedTextField( label = { Text(text = "Password") }, value = password, onValueChange = { password = it }, visualTransformation = PasswordVisualTransformation() ) OutlinedButton( modifier = Modifier.fillMaxWidth(), onClick = { shouldShowSnackBar = username.isEmpty() || password.isEmpty() println("Button pressed: $shouldShowSnackBar") } ) { Text(text = "Submit") } } } }
修复方案2:直接在点击事件中处理(更简洁)
使用rememberCoroutineScope获取协程作用域,直接在按钮点击事件中判断并显示SnackBar,无需额外状态变量,每次点击都会触发协程执行:
@Composable fun Login() { var username by remember { mutableStateOf("") } var password by remember { mutableStateOf("") } val scaffoldState = rememberScaffoldState() val coroutineScope = rememberCoroutineScope() println("LoginScreen") Scaffold(scaffoldState = scaffoldState) { Column(modifier = Modifier.fillMaxWidth()) { OutlinedTextField( label = { Text(text = "Username") }, value = username, onValueChange = { username = it } ) OutlinedTextField( label = { Text(text = "Password") }, value = password, onValueChange = { password = it }, visualTransformation = PasswordVisualTransformation() ) OutlinedButton( modifier = Modifier.fillMaxWidth(), onClick = { if (username.isEmpty() || password.isEmpty()) { coroutineScope.launch { scaffoldState.snackbarHostState.showSnackbar( message = "Please enter a username and password", duration = SnackbarDuration.Short ) } } } ) { Text(text = "Submit") } } } }
内容的提问来源于stack exchange,提问作者ant2009
相关产品推荐
相关产品推荐

