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

React Next.js中useState与表单状态异常问题求助

React注册表单State修改失败及提交问题修复

问题背景

我是React新手,尝试实现简单注册表单时遇到以下问题:

  • 无法修改组件state
  • 出现无法读取state的错误,按方案修改后又出现新错误
  • 最终需求是获取用户输入的邮箱和密码,提交到PostgreSQL数据库

原代码如下:

表单组件文件

import {useState} from 'react'

// 错误:useState不能在组件外部声明并export
export const [inputs, setInputs] = useState({})

export  const handleChange = (event: any) => {
    const name = event.target.name
    const value = event.target.value
    setInputs(values => ({...values, [name]: value}))
}

export  const handleSubmit = (event: any) => {
    event.preventDefault()
    console.log(inputs)
}

type Props = {
  label: string
  placeholder?: string
  // 错误:onChange类型定义错误,未接收event参数
  onChange: () => void
  name?: string
  value?:  any
}

export const TextField = ({ label, onChange, placeholder, name, value }: Props) => {
  return (
    <div style={{width:'100%'}}>
      <div className='text-sm my-2'>{label}</div>
      <input
        className='border-blue-200 border-2 rounded focus:ring-blue-200 focus:border-blue-200 focus:outline-none px-2'
        style={{ height: '45px', maxWidth: '280px', width: '100%', backgroundColor: '#0D0D0D' }}
        placeholder={placeholder}
        onChange={onChange}
        name={name}
        value={value}
      />
    </div>
  )
}

Register页面代码

<form action="" method="post">
  <div className='flex flex-col flex-wrap gap-y-5'>
    {/* 错误:onChange写法错误,未传递event且未调用函数 */}
    <TextField  name="email" value={inputs.email || ""} label='Enter Your email address:' onChange={() => {handleChange}} />
    <TextField name="password" value={inputs.password || ""} label='Enter Your Password:' onChange={() => {handleChange}} />
  </div>

  <div className='mt-7 flex items-center gap-x-2'>
    {/* 错误:onClick写法错误,未传递event且表单未绑定onSubmit */}
    <PrimaryButton text='Register' onClick={() => {handleSubmit}} />
    <div className='text-sm'>
      Already Registered? <a onClick={() => push('/login')}>Login</a>
    </div>
  </div>
</form>

错误原因分析

  1. useState使用错误:useState是React Hook,必须在函数组件内部调用,不能在组件外部声明并export,否则违反Hook规则。
  2. 事件处理传递错误:onChange={() => {handleChange}}仅返回函数引用,未实际调用也未传递event参数,无法触发state更新。
  3. Props类型定义错误:TextField的onChange类型定义为无参函数,但实际需要接收ChangeEvent参数,导致类型不匹配报错。
  4. 表单提交逻辑错误:表单未绑定onSubmit事件,仅靠按钮onClick调用handleSubmit不符合React表单规范,且未阻止默认跳转行为。

修正后的完整代码

1. TextField组件(单独文件:TextField.tsx)

import React from 'react';

type TextFieldProps = {
  label: string;
  placeholder?: string;
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
  name: string;
  value: string;
};

export const TextField = ({ label, onChange, placeholder, name, value }: TextFieldProps) => {
  return (
    <div style={{ width: '100%' }}>
      <div className='text-sm my-2'>{label}</div>
      <input
        className='border-blue-200 border-2 rounded focus:ring-blue-200 focus:border-blue-200 focus:outline-none px-2'
        style={{ height: '45px', maxWidth: '280px', width: '100%', backgroundColor: '#0D0D0D' }}
        placeholder={placeholder}
        onChange={onChange}
        name={name}
        value={value}
        type={name === 'password' ? 'password' : 'email'}
      />
    </div>
  );
};

2. Register页面组件(文件:Register.tsx)

import { useState } from 'react';
import { TextField } from './TextField';
import { PrimaryButton } from './PrimaryButton';
import { useRouter } from 'next/router'; // 根据项目路由库调整

export const Register = () => {
  const [inputs, setInputs] = useState({ email: '', password: '' });
  const router = useRouter();

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = event.target;
    setInputs(prev => ({ ...prev, [name]: value }));
  };

  const handleSubmit = async (event: React.FormEvent) => {
    event.preventDefault();
    // 基础输入验证
    if (!inputs.email || !inputs.password) {
      alert('请填写完整信息');
      return;
    }

    try {
      // 发送请求到后端接口,提交数据到PostgreSQL
      const response = await fetch('/api/register', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(inputs),
      });

      if (response.ok) {
        alert('注册成功');
        router.push('/login');
      } else {
        const errorData = await response.json();
        alert(`注册失败:${errorData.message}`);
      }
    } catch (error) {
      console.error('注册请求出错:', error);
      alert('网络错误,请稍后重试');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <div className='flex flex-col flex-wrap gap-y-5'>
        <TextField
          name="email"
          value={inputs.email}
          label='输入邮箱地址:'
          onChange={handleChange}
          placeholder='example@mail.com'
        />
        <TextField
          name="password"
          value={inputs.password}
          label='输入密码:'
          onChange={handleChange}
          placeholder='至少6位字符'
        />
      </div>

      <div className='mt-7 flex items-center gap-x-2'>
        <PrimaryButton text='注册' type="submit" />
        <div className='text-sm'>
          已有账号?<span onClick={() => router.push('/login')} style={{ cursor: 'pointer', color: 'blue' }}>登录</span>
        </div>
      </div>
    </form>
  );
};

提交到PostgreSQL的后端补充说明

需要后端接口(示例用Node.js + Express + PostgreSQL)处理前端请求:

const express = require('express');
const router = express.Router();
const { Pool } = require('pg');
const bcrypt = require('bcrypt'); // 用于密码加密

// PostgreSQL连接配置
const pool = new Pool({
  user: '你的数据库用户名',
  host: 'localhost',
  database: '你的数据库名',
  password: '你的数据库密码',
  port: 5432,
});

router.post('/register', async (req, res) => {
  const { email, password } = req.body;

  try {
    // 检查邮箱是否已注册
    const existingUser = await pool.query('SELECT * FROM users WHERE email = $1', [email]);
    if (existingUser.rows.length > 0) {
      return res.status(400).json({ message: '邮箱已被注册' });
    }

    // 加密密码
    const saltRounds = 10;
    const hashedPassword = await bcrypt.hash(password, saltRounds);

    // 插入新用户到数据库
    const result = await pool.query(
      'INSERT INTO users (email, password) VALUES ($1, $2) RETURNING *',
      [email, hashedPassword]
    );

    res.status(201).json({ message: '注册成功', user: result.rows[0] });
  } catch (error) {
    console.error('数据库错误:', error);
    res.status(500).json({ message: '服务器内部错误' });
  }
});

module.exports = router;

注意:必须对密码加密存储,禁止明文保存,示例中使用bcrypt库实现加密。

内容的提问来源于stack exchange,提问作者Gokuhan21

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 16:05:15