SwiftUI中Firebase Auth登录后如何等待Firestore异步拉取用户数据再展示
解决方案
1. 新增状态变量控制UI展示逻辑
你需要在页面中定义状态来标记数据拉取的不同阶段,推荐用枚举管理,可读性更强:
enum DataLoadingState { case loading // 拉取中 case success(User) // 拉取成功,关联拿到的用户数据 case failed(Error) // 拉取失败,关联错误信息 } // 在你的View中新增状态 @State private var loadState: DataLoadingState = .loading // 如果是放在全局数据管理类里,就用@Published // @Published var loadState: DataLoadingState = .loading
如果只需要简单控制,也可以用两个布尔值搭配存储用户数据的属性:
@State private var isLoading = true @State private var user: User? // 替换为你自己定义的用户数据模型
2. 修正异步方法调用逻辑
onAppear本身不支持异步上下文,你需要用Task包裹异步方法调用,同时调整数据读取方法,把拉取到的结果同步到状态中:
首先修改readUser方法,返回拿到的用户数据或者抛出错误:
func readUser(userID: String) async throws -> User { let userRef = database.collection("users") let doc = try await userRef.document(userID).getDocument() guard let docData = doc.data() else { throw NSError(domain: "FirestoreError", code: -1, userInfo: [NSLocalizedDescriptionKey: "用户数据不存在"]) } // 这里把docData转换成你自己定义的User模型,示例如下,也可以用你习惯的映射方式 let jsonData = try JSONSerialization.data(withJSONObject: docData) return try JSONDecoder().decode(User.self, from: jsonData) }
然后修改checkDatabase方法,同步拉取结果到状态:
func checkDatabase() async { guard self.pullUserData else { return } do { let user = try await dbm.readUser(userID: "VSWAq7QCw3dbGYwMdtClbbANGVe2") // 拉取成功更新状态 self.loadState = .success(user) // 如果用布尔值控制的话就写: // self.user = user // self.isLoading = false } catch { // 拉取失败更新状态 self.loadState = .failed(error) // 如果用布尔值控制的话就写: // self.isLoading = false } }
最后修正onAppear的触发逻辑:
.onAppear { Task { await pulluserData() } }
3. 根据状态渲染对应UI
在页面的body中根据状态返回不同的展示内容即可:
var body: some View { switch loadState { case .loading: ProgressView("加载中...") // 拉取中展示加载动画 case .success(let user): // 拉取成功后展示用户数据和关联内容 VStack { Text(user.name) Text(user.email) // 其他需要展示的内容 } case .failed(let error): // 拉取失败展示错误提示和重试按钮 VStack { Text("数据加载失败:\(error.localizedDescription)") Button("重试") { Task { await pulluserData() } } } } }
如果用布尔值控制的话写法如下:
var body: some View { if isLoading { ProgressView("加载中...") } else if let user = user { VStack { Text(user.name) // 其他需要展示的内容 } } else { VStack { Text("数据加载失败") Button("重试") { Task { await pulluserData() } } } } }
内容的提问来源于stack exchange,提问作者mdav132
相关产品推荐
相关产品推荐

