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

使用AutoRouter异步操作后导航遇上下文失效问题求助

解决AutoRouter导航时"Looking up a deactivated widget's ancestor is unsafe"错误

问题根源

当你在异步回调(比如signIn().then(...))中使用context获取AutoRouter时,登录页面可能已经因为PageView切换、Widget树更新等原因被移出渲染树,导致context对应的Widget已被deactivate/dispose,此时访问其祖先(AutoRouter)就会触发该错误。而你尝试的if (context.mounted)判断失效,正是因为异步操作完成时页面已经被卸载。

可行解决方案

方案1:提前缓存AutoRouter实例

在登录页面的State类中,提前在didChangeDependencies方法中获取AutoRouter实例并缓存,避免在异步回调中依赖context:

class _LoginPageState extends State<LoginPage> {
  late final AutoRouter _autoRouter;
  late final TextEditingController emailController;
  late final TextEditingController passwordController;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    // 在依赖变更时获取并缓存AutoRouter实例
    _autoRouter = AutoRouter.of(context);
  }

  @override
  void initState() {
    super.initState();
    emailController = TextEditingController();
    passwordController = TextEditingController();
  }

  @override
  void dispose() {
    emailController.dispose();
    passwordController.dispose();
    super.dispose();
  }

  void _onSignInPressed() {
    Provider.of<AuthProvider>(context, listen: false)
        .signIn(emailController.text, passwordController.text)
        .then((_) {
          // 使用缓存的AutoRouter实例执行导航
          _autoRouter.popAndPush(const HomeRoute());
        }).catchError((err) {
          // 处理登录失败逻辑
        });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 登录页面UI,按钮点击绑定_onSignInPressed
      body: Column(
        children: [
          TextField(controller: emailController),
          TextField(controller: passwordController),
          ElevatedButton(onPressed: _onSignInPressed, child: const Text("登录")),
        ],
      ),
    );
  }
}

方案2:通过状态监听解耦导航逻辑(更推荐)

让AuthProvider管理登录状态,登录页面监听状态变化触发导航,彻底避免依赖异步回调中的context:

1. 更新AuthProvider添加状态通知

class AuthProvider extends ChangeNotifier {
  bool _hasSignedIn = false;
  bool get hasSignedIn => _hasSignedIn;

  Future<void> signIn(String email, String password) async {
    // 执行实际登录逻辑(接口调用、本地存储等)
    // ...
    
    // 登录成功后更新状态并通知监听者
    _hasSignedIn = true;
    notifyListeners();
  }

  // 重置登录状态,避免重复触发导航
  void resetSignInState() {
    _hasSignedIn = false;
    notifyListeners();
  }
}

2. 登录页面监听状态并导航

class LoginPage extends StatelessWidget {
  final TextEditingController emailController = TextEditingController();
  final TextEditingController passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Consumer<AuthProvider>(
      builder: (context, authProvider, child) {
        // 在build完成后执行导航,避免触发重复渲染
        if (authProvider.hasSignedIn) {
          WidgetsBinding.instance.addPostFrameCallback((_) {
            AutoRouter.of(context).popAndPush(const HomeRoute());
            authProvider.resetSignInState();
          });
        }

        return Scaffold(
          body: Column(
            children: [
              TextField(controller: emailController),
              TextField(controller: passwordController),
              ElevatedButton(
                onPressed: () => authProvider.signIn(
                  emailController.text,
                  passwordController.text,
                ),
                child: const Text("登录"),
              ),
            ],
          ),
        );
      },
    );
  }
}

方案3:防止PageView卸载登录页面

如果登录页在PageView中,默认情况下滑走的页面会被dispose,可通过AutomaticKeepAliveClientMixin保持页面存活:

class LoginPage extends StatefulWidget {
  const LoginPage({super.key});

  @override
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> with AutomaticKeepAliveClientMixin {
  // 启用页面存活
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    // 必须调用super.build
    super.build(context);
    // 登录页面UI
    return ...;
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 02:55:32