You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 07:25:29