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
相关产品推荐
相关产品推荐

