You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter登录页Firebase认证:异步间隙警告与加载状态优化问题

解决方案

核心修改点

  1. 移除弹窗加载,改用按钮内进度指示器:既满足需求,又避免跨异步间隙使用context的警告
  2. 严格管理isLoading状态:防止重复触发登录操作,同时确保状态更新仅在组件挂载时执行
  3. 优化错误状态重置:用户输入新内容时自动清除错误提示

修改后的完整代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 03:47:09