React JS使用模块化Firebase v9操作Firestore报indexOf未定义错误如何解决
问题根因
你触发报错的核心原因有两个:
- React的
setState是异步更新,调用setUserData(user)之后,同步代码里访问userData拿不到刚生成的用户对象,此时userData还是初始的空字符串,userData.uid为undefined,传给Firestore路径参数时,Firestore内部调用indexOf处理路径字符串时拿到非有效值,直接抛出异常。 - Firestore API使用不符合需求:你要使用用户uid作为自定义文档ID存储数据,不能用
addDoc(addDoc是给集合自动生成随机文档ID的API),需要搭配doc和setDoc实现指定ID文档的写入。
修复后的代码
import React, { useState, useCallback } from 'react' import { auth, db } from "../firebase" import { createUserWithEmailAndPassword } from "firebase/auth"; import { doc, setDoc } from "firebase/firestore"; function Login() { const [email, setEmail] = useState('') const [pass, setPass] = useState('') const [error, setError] = useState('') const ProcessData = e => { e.preventDefault() registro() } const registro = useCallback(async() => { try { // 直接await获取认证返回的用户凭证,不需要通过状态中转 const userCredential = await createUserWithEmailAndPassword(auth, email, pass) const user = userCredential.user; // 用当前拿到的用户uid作为文档ID,写入数据 await setDoc(doc(db, 'users', user.uid), { email: user.email, uid: user.uid }) setEmail('') setPass('') setError('') } catch (error) { const errorMessage = error.message; setError(errorMessage) console.log(error) } // 依赖仅保留email和pass即可,移除不必要的依赖避免重复触发逻辑 }, [email, pass]) return ( <div> <h3>Registro</h3> <form onSubmit={ProcessData}> <label>Email Adress</label> <input type="email" placeholder="Email Address" onChange={e => setEmail(e.target.value)} value={email} /> <label>Password</label> <input type="password" placeholder="Password" onChange={e => setPass(e.target.value)} value={pass} /> <button type="submit">Registrarse</button> {error && <p style={{color: 'red'}}>{error}</p>} </form> </div> ) } export default Login
额外优化说明
- 移除了不必要的
userData状态,避免异步状态更新带来的逻辑异常 - 清理了未使用的
addDoc、collection导入,减少冗余代码 - 新增了错误信息的前端展示,方便用户感知操作异常
内容的提问来源于stack exchange,提问作者iandev
相关产品推荐
相关产品推荐

