React+TypeScript表单刷新后二次提交报错问题
问题分析与解决方案
核心问题
- DOM元素获取时机错误:在组件顶层直接调用
document.querySelector('.register-form'),组件渲染时DOM可能还未挂载完成。首次提交时侥幸拿到了DOM元素,但刷新后组件重新渲染的时序变化会导致registerForm为null,点击按钮访问其属性时直接抛出错误。 - PrismaClient重复实例化:每次组件渲染都创建新的
PrismaClient实例,会导致数据库连接泄漏,刷新后多次实例化会触发Prisma的连接数超标警告或报错。 - 表单处理不符合React规范:直接操作DOM获取表单值的方式违背了React的数据流模式,容易出现不可控的DOM引用问题。
修复后的代码
首先创建PrismaClient单例文件:
// prisma/client.ts import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() export default prisma
然后修改Register组件:
import { Link } from 'react-router-dom' import prisma from '../prisma/client' import './Register.css' import { useRef } from 'react' const Register = () => { const registerFormRef = useRef<HTMLFormElement>(null) interface User{ firstname: string email: string password: string } async function registerNewUser(userData: User) { try { const createUser = await prisma.user.create({ data: { name: userData.firstname, email: userData.email, password: userData.password } }) console.log('用户创建成功:', createUser) } catch (error) { console.error('创建用户失败:', error) } console.log(userData) } const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault() if (!registerFormRef.current) return const formData = new FormData(registerFormRef.current) const firstname = formData.get('firstname') as string const email = formData.get('email') as string const password = formData.get('password') as string const newUser: User = { firstname, email, password } registerNewUser(newUser) } return ( <div className="register-card" id='form'> <h2>Register</h2> <form className="register-form" ref={registerFormRef} onSubmit={handleSubmit}> <input type="text" name="firstname" placeholder="firstname" required /> <input type="email" name="email" placeholder="email" required /> <input type="password" name="password" placeholder="password" required /> <button type="submit">Register</button> </form> <Link to="/"><p>I have an account</p></Link> </div> ) } export default Register;
关键修复点
- 用
useRef获取表单元素:确保在DOM完全挂载后才能拿到有效引用,避免null报错。 - PrismaClient单例化:全局只创建一个PrismaClient实例,防止数据库连接泄漏。
- 改用form的
onSubmit事件:符合HTML表单原生行为,比按钮onClick更可靠。 - 用
FormData获取表单值:替代直接操作DOM元素的方式,更符合React的开发模式(也可以改用受控组件,用useState绑定每个输入框的值)。
内容的提问来源于stack exchange,提问作者Baziovsky
相关产品推荐
相关产品推荐

