React中无法向Firestore创建users集合并写入数据求助
问题分析与解决方案
核心问题
你的代码中,navigate('/login')在启动文件上传后直接执行,没有等待文件上传、用户资料更新以及Firestore写入这些异步操作完成。页面跳转后,未完成的异步任务可能被中断,导致Firestore数据写入失败。
另外还有两处细节问题:
uploadTask.on的完成状态回调未正确接收快照参数,不符合官方回调规范setDoc的错误被内部捕获但未向外抛出,外层try/catch无法感知写入失败
修复步骤
- 将文件上传逻辑封装为Promise,用
await等待所有异步操作完成后再跳转页面 - 修正
uploadTask.on的回调参数,确保正确监听上传状态 - 统一错误处理,让所有异常能被外层
try/catch捕获
修改后的代码
import React,{useState} from 'react' import {useNavigate} from 'react-router-dom' import { BsPersonBadge } from "react-icons/bs" import { createUserWithEmailAndPassword ,updateProfile } from "firebase/auth" import {auth ,storage,db} from '../../firebase' import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage"; import { setDoc ,doc } from "firebase/firestore" function SignUp() { const navigate = useNavigate() const [err , setErr] =useState(false) const handleSubmit = async (e) =>{ e.preventDefault() const displayName = e.target[0].value const email = e.target[1].value const password = e.target[2].value const file = e.target[3].files[0] // 校验是否选择文件 if (!file) { setErr(true) return } try{ // 创建用户 const res = await createUserWithEmailAndPassword(auth, email, password) // 初始化存储引用 const storageRef = ref(storage, displayName); const uploadTask = uploadBytesResumable(storageRef, file); // 将上传操作转为Promise,方便await等待完成 await new Promise((resolve, reject) => { uploadTask.on( 'state_changed', (snapshot) => { // 可选:监听上传进度 const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; console.log(`Upload is ${progress}% done`); }, (error) => { // 上传失败,拒绝Promise setErr(true) reject(error) }, async () => { // 上传完成,获取下载链接 const downloadURL = await getDownloadURL(uploadTask.snapshot.ref); // 更新用户资料 await updateProfile(res.user,{ displayName, photoURL:downloadURL }) // 写入Firestore await setDoc(doc(db, "users", res.user.uid), { uid: res.user.uid, displayName, email, photoURL:downloadURL }) // 所有操作完成,resolve Promise resolve() } ) }) // 所有异步操作完成后再跳转 navigate('/login') } catch(error){ setErr(true) console.log(error) } } return ( <section className='w-full min-h-screen text-white flex flex-col items-center justify-center bg-gradient-to-b from-neutral to-slate-900'> <div className='card lg:card-side bg-slate-900 '> <div className='card-body flex items-center justify-center'> <BsPersonBadge style={{color:'#ce024d', height:'auto',width:200}}/> </div> <div className='divider divider-primary divider-horizontal sm:divider-vertical'></div> <div className='card-body mx-auto'> <h1 className='text-4xl text-center'>Register</h1> <form onSubmit={handleSubmit} className='form-control card-body text-black gap-4'> <input type="text" placeholder="Display Name " className="input input-ghost input-md input-bordered w-full max-w-xs" /> <input type="email" placeholder="Email" className="input input-ghost input-md input-bordered w-full max-w-xs" /> <input type="password" placeholder="Password" className="input input-ghost input-md input-bordered w-full max-w-xs" /> <input type="file" className="file-input file-input-sm file-input-ghost text-white file-input-accent w-full max-w-xs" /> <div className='card-actions '> <button type='submit' className='btn btn-md btn-accent'>Sign Up</button> </div> <p className='text-white'>Already have an account?<span className='link link-accent' onClick={()=>navigate('/login')}>Login</span></p> </form> </div> </div> </section> ) } export default SignUp
额外检查项
- Firestore权限规则:确保规则允许已认证用户写入
users集合,示例规则如下:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow read, write: if request.auth != null && request.auth.uid == userId; } } }
- Firebase初始化:确认
../../firebase中的db实例已正确初始化,没有配置错误。
内容的提问来源于stack exchange,提问作者Evan Feliza
相关产品推荐
相关产品推荐

