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

React+TypeScript表单刷新后二次提交报错问题

问题分析与解决方案

核心问题

  1. DOM元素获取时机错误:在组件顶层直接调用document.querySelector('.register-form'),组件渲染时DOM可能还未挂载完成。首次提交时侥幸拿到了DOM元素,但刷新后组件重新渲染的时序变化会导致registerForm为null,点击按钮访问其属性时直接抛出错误。
  2. PrismaClient重复实例化:每次组件渲染都创建新的PrismaClient实例,会导致数据库连接泄漏,刷新后多次实例化会触发Prisma的连接数超标警告或报错。
  3. 表单处理不符合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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 08:50:30