使用Firebase的createUserWithEmailAndPassword添加自定义属性遇displayName为null问题
问题:Firebase创建用户时
displayName存入集合始终为null 使用Firebase的createUserWithEmailAndPassword()创建新用户,同时将用户信息存入users集合(文档以用户UID作为ID),其他功能正常,但存入集合的displayName始终为null。输入时console.log(newUser.username)能输出正确用户名,说明表单事件处理逻辑没问题。
相关代码:
const [newUser, setNewUser] = React.useState( { email: "", username: "", password: "", }) const handleNewUserFormSubmit = (e) => { const { name, value } = e.target; setNewUser({ ...newUser, [name]: value, }) } const createNewUser = () => { createUserWithEmailAndPassword(auth, newUser.email, newUser.password) .then((userCredential) => { console.log(newUser.username) const user = userCredential.user; const userRef = doc(db, "users", user.uid); setDoc(userRef, { displayName: newUser.username, email: newUser.email, profileURL: "", userId: user.uid, createdAt: Timestamp.fromDate(new Date()), }) }).then(() => { navigate("../channels") }) }
UI代码:
<Box className="primary-title"> <Typography variant="h5"> Create an account </Typography> </Box> <Box className="input-position"> <Box className="form-group"> <FormHelperText className="input-placeholder">Email</FormHelperText> <input className="form-style" type="email" name='email' onChange={e => handleNewUserFormSubmit(e)} style={{ marginBottom: "20px" }} /> </Box> <Box className="form-group"> <FormHelperText className="input-placeholder">username</FormHelperText> <input className="form-style" type="text" name='username' onChange={e => handleNewUserFormSubmit(e)} style={{ marginBottom: "20px" }} /> </Box> <Box className="form-group"> <FormHelperText id="outlined-weight-helper-text" className="input-placeholder">Password</FormHelperText> <input className="form-style" type="password" name="password" onChange={e => handleNewUserFormSubmit(e)} style={{ marginBottom: "20px" }} /> </Box> </Box> <Box className="btn-position"> <Button className="btn" onClick={createNewUser}>Continue</Button> </Box> <Box component="span" className="register-container"><Link to="/" className="link">Already have an account?</Link></Box>
修复方案
1. 解决React状态异步更新的问题
React的setState是异步操作,虽然console.log(newUser.username)能输出值,但实际执行setDoc时可能拿到的还是旧的state值。可以用下面两种方法解决:
方法一:用useRef跟踪实时表单值
把useState换成useRef,直接操作current属性存储实时输入值,避免异步更新的延迟:
// 替换原useState定义 const newUserRef = React.useRef({ email: "", username: "", password: "", }) // 修改表单事件处理函数 const handleNewUserFormSubmit = (e) => { const { name, value } = e.target; newUserRef.current = { ...newUserRef.current, [name]: value, } } // 修改创建用户函数 const createNewUser = () => { const { email, username, password } = newUserRef.current; createUserWithEmailAndPassword(auth, email, password) .then((userCredential) => { const user = userCredential.user; const userRef = doc(db, "users", user.uid); // 务必return这个Promise,确保后续跳转在数据写入后执行 return setDoc(userRef, { displayName: username, email: email, profileURL: "", userId: user.uid, createdAt: Timestamp.fromDate(new Date()), }) }).then(() => { navigate("../channels") }) }
方法二:提交时直接从DOM获取最新值
如果不想修改状态管理方式,直接在提交时从input元素拿到实时值:
const createNewUser = () => { // 从DOM获取当前输入值 const email = document.querySelector('input[name="email"]').value; const username = document.querySelector('input[name="username"]').value; const password = document.querySelector('input[name="password"]').value; createUserWithEmailAndPassword(auth, email, password) .then((userCredential) => { const user = userCredential.user; const userRef = doc(db, "users", user.uid); return setDoc(userRef, { displayName: username, email: email, profileURL: "", userId: user.uid, createdAt: Timestamp.fromDate(new Date()), }) }).then(() => { navigate("../channels") }) }
2. 确保Promise链式调用顺序正确
原代码中第二个then没有等待setDoc完成就跳转,虽然不直接导致displayName为null,但可能出现用户跳转后数据还没写入数据库的情况。上面的修复代码已经通过return setDoc(...)确保了跳转在数据写入完成后执行。
内容的提问来源于stack exchange,提问作者AnthonyDev220
相关产品推荐
相关产品推荐

