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

使用Riverpod的StateNotifier调用when方法遇空安全及类型错误

问题:Riverpod StateNotifier调用when方法报错处理

尝试使用Riverpod的StateNotifier实现认证功能时,调用when方法遇到以下报错:

  • 初始报错:The method 'when' can't be unconditionally invoked because the receiver can be 'null'
  • 添加!强制非空后报错:The method 'when' isn't defined for the type 'Object'

相关代码

MainPage代码

class MainPage extends ConsumerWidget {
  const MainPage({super.key});
  @override
  Widget build(BuildContext context, WidgetRef ref) {
  final state = ref.watch(emailPasswordSignInControllerProvider);

  return state.when(
    data: (state) {
      return state == AuthState.authenticated
          ? const SharedLayout()
          : const LoginScreen();
    },
    error: (error, stackTrace) => const Scaffold(
      body: Center(child: Text("Error")),
    ),
    loading: () => const Scaffold(
      body: Center(
        child: CircularProgressIndicator(),
      ),
    ),
  );
}

控制器代码

class EmailPasswordSignInController extends StateNotifier<AsyncValue<AuthState>> {
  EmailPasswordSignInController({required this.authRepository})
      : super(const AsyncValue.data(AuthState.notAuthenticated));
  final AuthRepository authRepository;

  Future<void> submit(String email, String password) async {
    try {
      state = const AsyncValue.loading();
      await authRepository.signInWithEmailAndPassword(email, password);
      state = const AsyncValue.data(AuthState.authenticated);
    } catch (e, st) {
      state = AsyncValue.error(e, st);
    }
  }
}

final emailPasswordSignInControllerProvider = StateNotifierProvider((ref) {
  final authRepository = ref.watch(authRepositoryProvider);
  return EmailPasswordSignInController(authRepository: authRepository);
});

仓库代码

class AuthRepository {
  Future<String> signInWithEmailAndPassword(
    String email, 
    String password,
  ) async {
    try {
      final String token;
      final Map<String, dynamic> jsonData;
      final url = Uri.parse('http://192.168.1.9:5000/api/v1/auth/login');
      final response = await http.post(url,
          body: jsonEncode({
            "email": email,
            "password": password,
          }),
          headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
          });
      jsonData = jsonDecode(response.body);
      if (response.statusCode == 200) {
        token = jsonData['token'];
        return token;
      }
      return "error";
    } on Exception catch (e) {
      print(e.toString());
      return e.toString();
    }
  }
}

final authRepositoryProvider = Provider<AuthRepository>((ref) {
  return AuthRepository();
});

解决方案

问题根源是StateNotifierProvider未指定泛型参数,默认会推断为StateNotifierProvider<Object, Object>,导致ref.watch返回Object类型,既没有when方法,也会触发空安全报错。

修复步骤:

  1. 给emailPasswordSignInControllerProvider添加完整泛型约束,明确StateNotifier子类和状态类型:
final emailPasswordSignInControllerProvider = StateNotifierProvider<EmailPasswordSignInController, AsyncValue<AuthState>>((ref) {
  final authRepository = ref.watch(authRepositoryProvider);
  return EmailPasswordSignInController(authRepository: authRepository);
});
  1. 修改后,MainPage中ref.watch会正确返回AsyncValue<AuthState>类型,直接调用when方法即可,无需添加!强制非空。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:20:27