Flutter登录页Firebase认证:异步间隙警告与加载状态优化问题
解决方案
核心修改点
- 移除弹窗加载,改用按钮内进度指示器:既满足需求,又避免跨异步间隙使用
context的警告 - 严格管理
isLoading状态:防止重复触发登录操作,同时确保状态更新仅在组件挂载时执行 - 优化错误状态重置:用户输入新内容时自动清除错误提示
修改后的完整代码
import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import '../services/auth/db_handler.dart'; class LoginPage extends StatefulWidget { final void Function()? onTap; const LoginPage({super.key, required this.onTap}); @override State<LoginPage> createState() => _LoginPageState(); } class _LoginPageState extends State<LoginPage> { final emailController = TextEditingController(); final passwordController = TextEditingController(); final dbhandler = DBHandler(); bool loginfail = false; bool isLoading = false; @override void dispose() { emailController.dispose(); passwordController.dispose(); super.dispose(); } Future signIn() async { // 防止重复点击 if (isLoading) return; setState(() { isLoading = true; loginfail = false; // 开始登录时重置错误状态 }); try { await FirebaseAuth.instance.signInWithEmailAndPassword( email: emailController.text.trim(), password: passwordController.text.trim(), ); } catch (e) { // 仅在组件挂载时更新状态,避免跨异步警告 if (mounted) { setState(() { loginfail = true; }); } } finally { // 无论成功失败,都结束加载状态 if (mounted) { setState(() { isLoading = false; }); } } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[300], body: Padding( padding: const EdgeInsets.all(25.0), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon( Icons.login, size: 100, ), const SizedBox(height: 50), TextField( controller: emailController, cursorColor: Colors.white, textInputAction: TextInputAction.next, decoration: InputDecoration( labelText: 'Email', errorText: loginfail ? '' : null, ), // 用户输入时重置错误状态 onChanged: (_) { if (loginfail) setState(() => loginfail = false); }, ), const SizedBox(height: 5), TextField( controller: passwordController, cursorColor: Colors.white, textInputAction: TextInputAction.done, obscureText: true, // 密码框隐藏内容 decoration: InputDecoration( labelText: 'Password', errorText: loginfail ? '用户名或密码错误,请重试' : null, ), // 用户输入时重置错误状态 onChanged: (_) { if (loginfail) setState(() => loginfail = false); }, // 回车直接触发登录 onSubmitted: (_) => signIn(), ), const SizedBox(height: 20), CupertinoButton.filled( // 加载时禁用按钮 onPressed: isLoading ? null : signIn, child: isLoading ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) : const Text( '登录', style: TextStyle(fontSize: 19), ), ), const SizedBox(height: 24), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('还不是会员?'), const SizedBox(width: 4), GestureDetector( onTap: widget.onTap, child: const Text( '立即注册', style: TextStyle(fontWeight: FontWeight.bold), ), ) ], ), ], ), ), ), ); } }
关键说明
- 消除跨异步警告:在
setState前检查mounted,确保组件未被销毁时才更新状态 - 按钮内加载效果:通过
isLoading状态切换按钮内容,加载时禁用按钮防止重复操作 - AuthGate协同工作:登录成功后,
AuthGate监听的authStateChanges会自动触发页面跳转,无需手动调用Navigator - 用户体验优化:密码框添加隐藏效果,输入新内容时自动清除错误提示,回车可直接触发登录
内容的提问来源于stack exchange,提问作者Milan Labus
相关产品推荐
相关产品推荐

