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

React+Firebase注册页onChange致输入框频繁重置问题排查

React注册页面输入框频繁重置问题修复

问题根源

你把RootStyle、CssTextField这类通过Material-UI styled API创建的自定义组件,定义在了SignUp组件内部。每次输入内容触发状态更新时,SignUp组件会重新渲染,内部的styled组件会被重新创建。React会判定这些是全新的组件类型,进而卸载原有组件并重新挂载,直接导致输入框的状态被重置。

修复方案

把所有styled组件的定义移到SignUp组件外部,确保它们只被初始化一次,不会随组件渲染重复创建。同时补上LastName输入框的状态绑定,完善表单功能。

修复后的完整代码

import React,{useState,useContext} from 'react';
import Button from '@mui/material/Button';
import TextField from '@mui/material/TextField';
import Link from '@mui/material/Link';
import Grid from '@mui/material/Grid';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import Container from '@mui/material/Container';
import { styled } from '@mui/material';
import Logo from '../assets/QpiVolta-Logo.png'
import { useTheme,IconButton } from '@mui/material';
import { tokens } from '../theme';
import {Person,Lock, Mail, Visibility, VisibilityOff} from '@mui/icons-material';
import { useNavigate } from 'react-router-dom';
import { UserAuth } from '../context/AuthContext';

// 将styled组件移到组件外部
const RootStyle = styled("div")(({ theme }) => {
  const colors = tokens(theme.palette.mode);
  return {
    backgroundColor:"#d4cbf6",
    background:`${colors.primary[400]} !important`,
    height: "100vh",
    display: "flex",
    placeItems: "center",
  }
});

const CssTextField = styled(TextField)(({ theme }) => {
  const colors = tokens(theme.palette.mode);
  return {
    '& label.Mui-focused': {
      color: `${colors.pinkAccent[500]}`,
    },
    '& .MuiInput-underline:after': {
      borderBottomColor:  `${colors.pinkAccent[500]}`,
    },
    '& .MuiOutlinedInput-root': {
      '& fieldset': {
        borderColor: 'grey',
      },
      '&:hover fieldset': {
        borderColor: `${colors.pinkAccent[500]}`,
      },
      '&.Mui-focused fieldset': {
        borderColor: `${colors.pinkAccent[500]}`,
      },
    },
  }
});

const SignUp = () => {
  const theme = useTheme();
  const colors = tokens(theme.palette.mode);
  
  const [showPassword, setShowPassword] = useState(false);
  const handleClickShowPassword = () => setShowPassword((show) => !show);

  const handleMouseDownPassword = (event) => {
    event.preventDefault();
  };

  const [email, setEmail] = useState("")
  const [password, setPassword] = useState("")
  const [firstName,setFirstName] = useState("")
  const [lastName,setLastName] = useState("") // 新增LastName状态
  const [error, setError] = useState("")
  const {signUp} = UserAuth()
  const navigate = useNavigate()
  
  const handleSubmit= async(e) => {
    e.preventDefault()
    try {
      await signUp(email,password)
      setError('')
      navigate('/') 
    }
    catch (error) {
      console.log(error)
      setError(error.message)
    }
  }
  
  const logoStyle = {
    height: '80px',
  };

  return (
    <RootStyle theme={theme}>
      <Container  maxWidth="sm" >
      <Box
        sx={{
          marginTop: 8,
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'center',            
        }}
      >
        
        <img component="img" src={Logo} style={logoStyle}  />
        <Typography component="h1" variant="h2" color={colors.grey[100]} >
          Create an account<span style={{ color:`${colors.pinkAccent[500]}`}}>.</span>
        </Typography>
        <Box component="form"  onSubmit={handleSubmit} sx={{ mt: 2 , mb:2}}>
          <Grid container spacing={3} >
            <Grid item xs={12} sm={6} >
            <Box sx={{ display: 'flex', alignItems: 'flex-end' }}>
            <Person sx={{ color: 'action.active', mr: 1, my: 0.5 }} />
            <CssTextField  
                fullWidth
                label="First Name" 
                id="FirstName"
                name="FirstName"
                autoComplete="family-name"
                variant='standard' 
                value={firstName}
                onChange={(e)=> setFirstName(e.target.value)}
            />
                </Box>
            </Grid>
            <Grid item xs={12} sm={6}>
            <Box sx={{ display: 'flex', alignItems: 'flex-end' }}>
            <Person sx={{ color: 'action.active', mr: 1, my: 0.5 }} />
              <CssTextField
                fullWidth
                id="lastName"
                label="Last Name"
                name="lastName"
                autoComplete="family-name"
                variant='standard' 
                value={lastName}
                onChange={(e)=> setLastName(e.target.value)} // 绑定LastName状态
              />
              </Box>
            </Grid>
            <Grid item xs={12}>
            <Box sx={{ display: 'flex', alignItems: 'flex-end' }}>
            <Mail sx={{ color: 'action.active', mr: 1, my: 0.5 }} />
              <CssTextField
                required
                fullWidth
                id="email"
                label="Email Address"
                name="email"
                value={email}
                autoComplete="email"
                variant='standard' 
                onChange={(e) => {
                  console.log(e.target.value);
                  setEmail(e.target.value);
                }}
              />
              </Box>
            </Grid>
            <Grid item xs={12}>
            <Box sx={{ display: 'flex', alignItems: 'flex-end' }}>
            <Lock sx={{ color: 'action.active', mr: 1, my: 0.5 }} />
              <CssTextField
                 required
                 fullWidth
                 name="password"
                 label="Password"
                 id="password"
                 autoComplete="new-password"
                 type={showPassword ? 'text' : 'password'}
                 variant='standard'
                 value={password}
                 onChange={(e) => setPassword(e.target.value)}
                 InputProps={{
                   endAdornment: (
                    <IconButton
                      aria-label="toggle password visibility"
                      onClick={handleClickShowPassword}
                      onMouseDown={handleMouseDownPassword}
                    >
                      {showPassword ? <Visibility /> : <VisibilityOff />}
                    </IconButton>
                   ),
                 }}
              />
              </Box>
            </Grid>
          </Grid>
          <Button
            type="submit"
            fullWidth
            variant="contained"
            sx={{ mt: 3, mb: 2 }}
          >
            Sign Up
          </Button>
          <Grid container justifyContent="flex-end">
            <Grid item>
              <Link href="/Login" variant="body2" sx={{color:"grey"}}>
                Already have an account? Sign in
              </Link>
            </Grid>
          </Grid>
        </Box>
      </Box>
    </Container>
    </RootStyle>    
  )
}

export default SignUp

额外说明

  • 调整了styled组件的定义方式,通过接收theme参数来获取colors,避免在组件内部重复计算。
  • 把原来的name状态改为firstName,新增lastName状态并绑定到对应的输入框,完善表单数据收集。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 15:45:18