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> ); }
问题原因与解决方案
原因分析
- JSX语法错误:Create1.js中
motion.div标签未正确闭合,缺少结束的>符号,导致组件每次状态更新时DOM结构异常重建,引发输入框失焦。 - 重复ID问题:InputField组件中TextField使用固定ID
"outlined-basic",多个实例会造成DOM元素ID重复,浏览器无法正确识别输入框,也会导致失焦问题。
解决方案
- 修复
motion.div的JSX语法,补充闭合符号,并确保标签层级正确嵌套。 - 给InputField的TextField设置唯一ID,通过传入的
name属性动态生成ID(如id={outlined-${name}}),同时在使用InputField时传递name属性(如<InputField name="firstName" ... />)。
完成上述修改后,输入框即可正常连续输入,不会再出现单次输入后失焦的问题。
内容的提问来源于stack exchange,提问作者Jasmine
相关产品推荐
相关产品推荐

