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

Riverpod代码生成器状态异常:页面状态无法稳定更新求助

Riverpod状态重置导致获取不到输入值问题排查

问题现象

  • 自定义appTextField的onChanged回调中,通过ref.read调用RegisterNotifier的onUserNameChanged更新状态时,实时打印状态能正常显示输入内容
  • 点击页面按钮通过SignUpController的handleSignUp方法调用ref.watch获取状态时,userName为空
  • 偶尔重启应用后能正常工作一段时间,但之后状态会被重置为新的RegisterState实例,导致状态变量为空,无法完成用户认证

相关代码片段

自定义TextField调用代码

appTextField(
  text: "Username",
  icon: "assets/icons/user.png",
  hintText: "Enter your username",
  func: (value) {
    ref
      .read(registerNotifierProvider.notifier)
      .onUserNameChanged(value);
      print(ref.watch(registerNotifierProvider).userName);
    },
  ),

RegisterNotifier实现

import 'package:elearningapp/pages/register_page/notifier/register_state.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'register_notifier.g.dart';

@riverpod
class RegisterNotifier extends _$RegisterNotifier {
  @override
  RegisterState build() {
    return RegisterState();
  }

  void onUserNameChanged(String name) {
    state = state.copyWith(userName: name);
  }

  void onUserEmailChanged(String email) {
    state = state.copyWith(email: email);
  }

  void onUserPasswordChanged(String password) {
    state = state.copyWith(password: password);
  }

  void onUserRePasswordChanged(String repassword) {
    state = state.copyWith(repassword: repassword);
  }
}

RegisterState类

class RegisterState {
  final String userName;
  final String email;
  final String password;
  final String repassword;

  RegisterState({
    this.userName = "",
    this.email = "",
    this.password = "",
    this.repassword = "",
  });

  RegisterState copyWith({
    String? userName,
    String? email,
    String? password,
    String? repassword,
  }) {
    return RegisterState(
      userName: userName ?? this.userName,
      email: email ?? this.email,
      password: password ?? this.password,
      repassword: repassword ?? this.repassword,
    );
  }
}

SignUpController实现

import 'package:elearningapp/pages/register_page/notifier/register_notifier.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class SingUpController {
  final WidgetRef ref;

  SingUpController({required this.ref});

  void handleSignUp() {
    var state = ref.watch(registerNotifierProvider);

    String name = state.userName;
    String email = state.email;
    String password = state.password;
    String rePassword = state.repassword;

    print("your name is : $name");
    
    // print("pass: $password");
    // print("repss; $rePassword");
  }
}

问题原因及解决方案

1. Provider被意外销毁(最可能原因)

Riverpod的Provider默认会在没有任何监听者时自动销毁,状态会重置为初始值。如果注册页面在场景切换(比如跳转其他页面、弹窗弹出/关闭)时,监听registerNotifierProvider的Widget被移除或停止监听,Provider就会被销毁,再次访问时会重新执行build()方法生成新的RegisterState实例。

解决方案:

  • 给Provider添加keepAlive修饰,让状态在无监听时也保持:
    修改RegisterNotifier的注解:
    @riverpod(keepAlive: true)
    class RegisterNotifier extends _$RegisterNotifier {
      // ... 原有代码
    }
    
  • 或者确保注册页面的根Widget始终监听该Provider(比如在页面build方法中调用ref.watch(registerNotifierProvider)),避免Provider失去监听者。

2. SignUpController的ref上下文错误

如果SingUpController初始化时传入的ref不是注册页面的WidgetRef(比如来自全局Provider、已销毁的Widget上下文),会导致获取到新的Provider实例。

解决方案:

  • 确保在注册页面内部初始化SingUpController,传入当前页面的WidgetRef:
    ElevatedButton(
      onPressed: () {
        SingUpController(ref: ref).handleSignUp();
      },
      child: Text("Sign Up"),
    )
    

3. 代码生成缓存问题

如果使用Riverpod代码生成器,旧的生成文件可能导致逻辑异常。

解决方案:

  • 重新运行代码生成命令,清除缓存:
    dart run build_runner watch --delete-conflicting-outputs
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 22:44:56