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

如何将AuthService类重构为StatefulWidget并正确处理异步后的BuildContext与mounted

解决「BuildContexts across async gaps」警告:重构AuthService为StatefulWidget

原AuthService类在异步操作后直接使用BuildContext,触发「BuildContexts across async gaps」警告——这是因为异步操作期间Widget可能已被销毁,此时使用无效上下文会引发错误。以下是重构方案:将Auth逻辑迁移至StatefulWidget的State类中,通过mounted属性验证上下文有效性。

重构后的完整代码

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:provider/provider.dart';
import 'dart:convert';

// 假设User、UserProvider、httpErrorHandle、showSnackBar、HomeScreen、uri已在其他文件定义

class AuthHandler extends StatefulWidget {
  final Widget child;

  const AuthHandler({super.key, required this.child});

  static AuthHandlerState of(BuildContext context) {
    return context.findAncestorStateOfType<AuthHandlerState>()!;
  }

  @override
  AuthHandlerState createState() => AuthHandlerState();
}

class AuthHandlerState extends State<AuthHandler> {
  // 注册用户
  void signUpUser({
    required String email,
    required String password,
    required String name,
  }) async {
    try {
      User user = User(
        id: '',
        name: name,
        password: password,
        email: email,
        address: '',
        type: '',
        token: '',
        // cart: [],
      );
      http.Response res = await http.post(
        Uri.parse('$uri/api/signup'),
        body: user.toJson(),
        headers: const <String, String>{
          'Content-Type': 'application/json; charset=UTF-8',
        },
      );

      // 验证Widget是否仍挂载,避免使用无效上下文
      if (!mounted) return;

      httpErrorHandle(
        response: res,
        context: context,
        onSuccess: () {
          showSnackBar(
            context,
            '账户创建成功!请使用相同凭证登录!',
          );
        },
      );
    } catch (e) {
      if (!mounted) return;
      showSnackBar(context, e.toString());
    }
  }

  // 登录用户
  void signInUser({
    required String email,
    required String password,
  }) async {
    try {
      http.Response res = await http.post(
        Uri.parse('$uri/api/signin'),
        body: jsonEncode({
          'email': email,
          'password': password,
        }),
        headers: const <String, String>{
          'Content-Type': 'application/json; charset=UTF-8',
        },
      );

      if (!mounted) return;

      httpErrorHandle(
        response: res,
        context: context,
        onSuccess: () async {
          SharedPreferences prefs = await SharedPreferences.getInstance();
          
          if (!mounted) return;
          Provider.of<UserProvider>(context, listen: false).setUser(res.body);
          
          await prefs.setString('x-auth-token', jsonDecode(res.body)['token']);
          
          if (!mounted) return;
          Navigator.pushNamedAndRemoveUntil(
            context,
            HomeScreen.routeName,
            (route) => false,
          );
        },
      );
    } catch (e) {
      if (!mounted) return;
      showSnackBar(context, e.toString());
    }
  }

  // 获取用户数据
  void getUserData() async {
    try {
      SharedPreferences prefs = await SharedPreferences.getInstance();
      String? token = prefs.getString('x-auth-token');

      if (token == null) {
        prefs.setString('x-auth-token', '');
      }

      var tokenRes = await http.post(
        Uri.parse('$uri/tokenIsValid'),
        headers: <String, String>{
          'Content-Type': 'application/json; charset=UTF-8',
          'x-auth-token': token!
        },
      );

      var response = jsonDecode(tokenRes.body);

      if (response == true) {
        http.Response userRes = await http.get(
          Uri.parse('$uri/'),
          headers: <String, String>{
            'Content-Type': 'application/json; charset=UTF-8',
            'x-auth-token': token
          },
        );

        if (!mounted) return;
        var userProvider = Provider.of<UserProvider>(context, listen: false);
        userProvider.setUser(userRes.body);
      }
    } catch (e) {
      if (!mounted) return;
      showSnackBar(context, e.toString());
    }
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

关键改动说明

  • 移除上下文传递:不再将BuildContext作为方法参数,直接使用State类的context属性,避免跨异步传递无效上下文
  • 挂载状态检查:所有异步操作(await后)添加if (!mounted) return;,确保Widget仍处于活跃状态才继续使用上下文
  • 全局访问入口:通过AuthHandler.of(context)静态方法,可在任意子Widget中获取AuthHandlerState实例,调用相关方法
  • 结构调整:将原AuthService的静态逻辑迁移至StatefulWidget的State类中,符合Flutter的Widget生命周期管理规范

使用方式

在Widget树的上层(如MaterialApp外层)添加AuthHandler:

void main() {
  runApp(
    AuthHandler(
      child: MaterialApp(
        // ... 其他配置
      ),
    ),
  );
}

在需要调用Auth方法的Widget中:

// 调用注册
AuthHandler.of(context).signUpUser(
  email: 'test@example.com',
  password: '123456',
  name: 'Test User',
);

// 调用登录
AuthHandler.of(context).signInUser(
  email: 'test@example.com',
  password: '123456',
);

// 获取用户数据
AuthHandler.of(context).getUserData();

内容的提问来源于stack exchange,提问作者marc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 10:10:28