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

React自定义MUI TextField仅能单次输入字符问题求助

自定义MUI TextField单次输入后失焦问题排查与解决

在React Web应用中使用自定义MUI TextField组件时遇到问题:每次仅能输入一个字符,输入后输入框立即失去焦点,需重新选中才能继续输入。已查阅相关资料,了解到该现象通常由组件嵌套定义导致,但在渲染InputField的Create1.js及InputField组件本身中均未存在组件嵌套情况。相关代码如下:

Create1.js 代码

import * as React from 'react';
import Box from '@mui/material/Box';
import styled from '@emotion/styled';
import RightBox from '../components/RightBox.jsx';
import CreateNavbar from '../components/CreateNavbar.js';
import LeftBox from '../components/LeftBox.js'
import { Typography } from "@mui/material"; 
import InputField from '../components/InputFIeld.js';
import {motion} from 'framer-motion';
import Dropdown from '../components/Dropdown.js';
import { useState } from 'react';

const FullPageCenter = styled('div')({
  display: 'flex',
  justifyContent: 'center',
  alignItems: 'center',
  minHeight: '100vh',
});

const ItalicText = styled('div')(({ theme }) => ({
  fontFamily: theme.typography.h1.fontFamily,
  fontStyle: 'italic',
  fontSize: '8rem',
  color: theme.palette.accent.main,
  lineHeight: '0.9',
}));

const Wrapper = styled('div')({
    justifyContent: 'center',
    alignItems: 'center',
    height: '45rem',
    width: '80rem',
    overflowX: 'hidden',
    overflowY: 'scroll',
    marginBottom: '4rem',
    position: 'relative',
});

const CenterContainer = styled(Box)(({ theme }) => ({
    width: '98%',
    display: 'flex',
    minHeight: '98%',
    height: '98%',
    margin: 'auto',
    marginTop: '4rem',
    overflowX: 'hidden',
    border: '1px solid black',
    overflowY: 'hidden',
  }));

const validages = [17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27];

const unilist = [
  "University of Toronto",
  "University of British Columbia",
  "McGill University",
  "McMaster University",
  "University of Montreal",
  "Concordia University",
  "Ryerson University",
  "Waterloo Univeristy"
]

export default function Create1() {

const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [age, setAge] = useState(0);
const [university, setUniversity] = useState('');

const handleFirstNameChange = (value) => setFirstName(value);
const handleLastNameChange = (value) => setLastName(value);
const handleAgeChange = (newValue) => setAge(newValue);
const handleUniversityChange = (newValue) => setUniversity(newValue);

  const handleSubmit = async () => {
    const payload = {
      firstName,
      lastName,
      age,
      university
    };
  
    console.log(payload);
  
    try {
      const response = await fetch('http://localhost:8080/auth/update1', {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(payload)
      });
  
      if (!response.ok) {
        const responseData = await response.json();
        console.error('Failed to submit data:', responseData);
      } else {
        console.log('Successfully submitted data!');
      }
    } catch (error) {
      console.error('There was a problem with the fetch operation:', error.message);
    }
  };
  

  return (
    <motion.div
      initial={{opacity: 0}}
      animate={{opacity: 1}}
      exit={{opacity: 0, transition: {duration: 0.4}}}
    >
      <FullPageCenter>
        <Wrapper>
          <CreateNavbar />
          <CenterContainer>
            <LeftBox>
              <ItalicText style={{marginLeft: '3rem', wordWrap:"break-word", overflowWrap: "break-word", marginBottom: '5rem',marginTop: '0.7rem'}}>"Introduce yourself!"</ItalicText> 
            </LeftBox>
            <RightBox>
              <InputField label="FIRST NAME" name="firstName" value={firstName} onChange={handleFirstNameChange} />
              <InputField label="LAST NAME" name="lastName" value={lastName} onChange={handleLastNameChange} />
              <Dropdown label="AGE" menuitems={validages} value={age} onChange={handleAgeChange}/>
              <Dropdown label="UNIVERSITY" menuitems={unilist} value={university} onChange={handleUniversityChange} />
              <button onClick={handleSubmit}>Submit</button>
            </RightBox>
          </CenterContainer>
        </Wrapper>
      </FullPageCenter>
    </motion.div>
  );
}

InputField组件代码

import * as React from 'react';
import TextField from '@mui/material/TextField';
import { useTheme } from '@mui/material/styles';
import { Typography } from '@mui/material';

export default function InputField({label, color, onChange, name, value}) {

  const theme = useTheme();

  const handleInputChange = (event) => {
    if (onChange) {
      onChange(event.target.value);
    }
  };

  return (
    <div>
      <Typography variant="body1" sx={{margin:0, fontSize:'0.85rem', color: color}}> {label}</Typography>  
      <TextField 
          id={`outlined-${name}`} 
          variant="outlined" 
          name={name}
          value={value}
          onChange={handleInputChange}
          sx={{ 
            width: '300px',
            margin: 0,
              '& .MuiInputBase-input': {
                  fontSize: '0.85rem', 
                  fontFamily: theme.typography.body1.fontFamily,
                  fontWeight: '300' 
              }
          }} 
      />
    </div>
  );
}

问题原因与解决方案

原因分析

  1. JSX语法错误:Create1.js中motion.div标签未正确闭合,缺少结束的>符号,导致组件每次状态更新时DOM结构异常重建,引发输入框失焦。
  2. 重复ID问题:InputField组件中TextField使用固定ID"outlined-basic",多个实例会造成DOM元素ID重复,浏览器无法正确识别输入框,也会导致失焦问题。

解决方案

  1. 修复motion.div的JSX语法,补充闭合符号,并确保标签层级正确嵌套。
  2. 给InputField的TextField设置唯一ID,通过传入的name属性动态生成ID(如id={outlined-${name}}),同时在使用InputField时传递name属性(如<InputField name="firstName" ... />)。

完成上述修改后,输入框即可正常连续输入,不会再出现单次输入后失焦的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 20:27:04