Next.js中document.getElementById取值与Firebase set报错咨询
问题原因
你遇到的报错有4个核心触发点,和你猜测的null有一定关联但不是根本原因:
- 首先
document.getElementById('userName')返回的是整个input DOM元素对象,不是输入框里的文本值,这个DOM对象挂载了React的内部属性__reactFiber$xxx,属性名带$这类Firebase Realtime Database禁止的特殊字符,你把整个DOM对象往数据库存的时候就会触发key非法的报错。 - 你的按钮事件写的是
onClick={ getValue() },等于组件渲染阶段就会立即执行getValue函数,根本不会等用户点击提交,这时候要么DOM还没挂载完成拿到null,要么用户还没输入内容,自然拿不到有效值。 - 你调用
writeUserData的时候参数传错了:函数定义要接收的第二个参数是用户名文本、第三个是地址字符串,你实际传的是{ userN }、{ address }两个对象,等于要存的数据结构完全不对。 - 额外问题:直接用
document.getElementById操作DOM是React/Next.js里不推荐的反模式,很容易出现时序问题、拿错元素的情况,表单提交也没阻止默认的页面刷新行为。
适配方案
用React推荐的受控组件模式实现就可以完全避开这些问题,不需要手动查询DOM:
- 用
useState存输入的用户名和地址状态 - 给input绑定onChange事件实时同步输入值
- 表单用onSubmit事件处理提交,记得调用
e.preventDefault()阻止默认刷新 - 提交的时候直接拿state里存的值传给数据库写入方法就行
修正后的完整代码参考:
'use client' // Next.js App Router下需要加这个标记为客户端组件 import { useState } from 'react' import { getDatabase, ref, set } from 'firebase/database' export default function Username() { const [address] = useState('') // 替换成你原本获取address的逻辑即可 const [userName, setUserName] = useState('') function writeUserData(userId, userN, walletAddr) { const db = getDatabase() const reference = ref(db, 'users/' + userId) set(reference, { username: userN, walletAddress: walletAddr }) } function handleSubmit(e) { // 阻止表单默认提交刷新页面 e.preventDefault() // 直接拿state里的输入值调用写入方法,无需操作DOM writeUserData('id', userName, address) } return ( <> <div> <p className="account-Info">address: {address}</p> </div> <div id="form"> <h2 className='user-Create'>Create Username</h2> <form id='set-User' onSubmit={handleSubmit}> <input id='userName' className='user-Create' type='text' placeholder="username" required minLength='3' maxLength='20' pattern="[a-zA-Z0-9_]+" title='only letters, numbers, and underscores' value={userName} onChange={(e) => setUserName(e.target.value)} /> <button className='user-Create' type="submit">Link Username</button> </form> </div> </> ) }
如果你一定要用原生DOM获取的方式(非常不推荐),至少要修正这几个点:
- 事件绑定改成
onClick={getValue}或者onClick={() => getValue()},不要加括号在渲染阶段直接执行函数 - 拿到DOM元素后取
.value属性才是输入的文本:const userN = document.getElementById('userName').value - 调用writeUserData的时候直接传值,不要包裹多余的对象:
writeUserData('id', userN, address) - 给点击/提交事件加
e.preventDefault()阻止默认页面刷新
内容的提问来源于stack exchange,提问作者user19333414
相关产品推荐
相关产品推荐

