Flutter中Firestore.instance.collection调用报‘undefined’错误求助
问题分析与解决方案
问题概述
在以下代码位置触发undefined报错:
FirebaseAuth auth = FirebaseAuth.instance; await Firestore.instance.collection('users').document(auth.currentUser.uid).setData({ 'levelTestTaken': true,
已导入Firebase相关依赖,但问题未解决,完整代码如下:
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'app/modules/auth_service/auth_controller/auth_controllers.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( initialRoute: '/splash', routes: { '/splash': (context) => SplashPage(), '/login': (context) => LoginPage(), '/level_test': (context) => LevelTestPage(), '/main': (context) => MainPage(), }, ); } } class SplashPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: FutureBuilder( future: _navigateToAppropriatePage(context), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return Container(); } else { return CircularProgressIndicator(); } }, ), ), ); } Future<void> _navigateToAppropriatePage(BuildContext context) async { FirebaseAuth auth = FirebaseAuth.instance; if (auth.currentUser == null) { Navigator.pushNamed(context, '/login'); } else { DocumentSnapshot userDoc = await Firestore.instance.collection('users').document(auth.currentUser.uid).get(); bool levelTestTaken = userDoc.data['levelTestTaken']; if (levelTestTaken) { Navigator.pushNamed(context, '/main'); } else { Navigator.pushNamed(context, '/level_test'); } } } } class LoginPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Text('Login Page'), ), ); } } class LevelTestPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: ElevatedButton( onPressed: () async { // Save the levelTestTaken information to the user's document in the Firestore database FirebaseAuth auth = FirebaseAuth.instance; await Firestore.instance.collection('users').document(auth.currentUser.uid).setData({ 'levelTestTaken': true, }, merge: true); Navigator.pushNamed(context, '/main'); }, child: Text('Complete Level Test'), ), ), ); } } class MainPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Text('Main Page'), ), ); } }
问题原因
- 用户状态未同步:Splash页的判断逻辑仅读取单次
auth.currentUser,跳转至LevelTestPage时,用户认证状态可能因异步更新变为null,导致访问uid触发undefined错误。 - Firestore API版本兼容:代码使用旧版Firestore API(
document()、setData()),在新版SDK中这些方法已废弃,存在兼容性问题。 - 字段/文档未初始化:若用户文档不存在或
levelTestTaken字段未定义,直接读取会引发异常。
解决方案
1. 安全校验用户状态
在访问用户ID前强制做非空校验,避免空指针:
onPressed: () async { FirebaseAuth auth = FirebaseAuth.instance; User? user = auth.currentUser; if (user != null) { await FirebaseFirestore.instance.collection('users').doc(user.uid).set({ 'levelTestTaken': true, }, SetOptions(merge: true)); Navigator.pushNamed(context, '/main'); } else { Navigator.pushNamed(context, '/login'); } },
2. 升级Firestore API到最新规范
替换旧版API为当前官方推荐用法:
Firestore.instance→FirebaseFirestore.instancedocument()→doc()setData()→set(),用SetOptions(merge: true)替代原merge参数
3. 优化用户状态监听逻辑
使用authStateChanges()实时监听用户状态,确保获取最新认证信息:
Future<void> _navigateToAppropriatePage(BuildContext context) async { FirebaseAuth auth = FirebaseAuth.instance; User? user = await auth.authStateChanges().first; if (user == null) { Navigator.pushNamed(context, '/login'); } else { DocumentSnapshot userDoc = await FirebaseFirestore.instance.collection('users').doc(user.uid).get(); bool levelTestTaken = userDoc.data()?['levelTestTaken'] ?? false; if (levelTestTaken) { Navigator.pushNamed(context, '/main'); } else { Navigator.pushNamed(context, '/level_test'); } } }
4. 初始化用户文档处理
若用户文档不存在,先创建默认文档再读取:
DocumentSnapshot userDoc = await FirebaseFirestore.instance.collection('users').doc(user.uid).get(); if (!userDoc.exists) { await FirebaseFirestore.instance.collection('users').doc(user.uid).set({ 'levelTestTaken': false, // 添加其他必要默认字段 }); } bool levelTestTaken = userDoc.data()?['levelTestTaken'] ?? false;
内容的提问来源于stack exchange,提问作者jonghwan
相关产品推荐
相关产品推荐

