React切换Autocomplete与TextField组件后输入内容丢失问题求助
问题描述
我有Autocomplete和TextField两个组件,要求同一时间仅展示其中一个:当输入内容包含斜杠(/)时显示TextField组件,否则显示Autocomplete组件。
我编写了如下代码:
export default function ComboBox() { const [show, setShow] = React.useState(false); const [value, setvalue] = React.useState(''); const onchange = (e) => { const inputValue = event?.target?.value || newValue || ''; setvalue(inputValue); setShow((prevState) => { const newState = inputValue?.includes('/'); if (prevState !== newState) { if (newState) { setTimeout(() => { document.getElementById('outlined-basic')?.focus(); }, 10); } else { setTimeout(() => { document.getElementById('combo-box-demo')?.focus(); }, 10); } } return newState; }); }; return ( <div> {show ? ( <TextField id="outlined-basic" label="Outlined" variant="outlined" value={value} onChange={onchange} /> ) : ( <Autocomplete disablePortal id="combo-box-demo" options={top100Films} inputValue={value} // defaultValue={'abc'} onInputChange={onchange} sx={{ width: 300 }} renderInput={(params) => <TextField {...params} label="Movie" />} /> )} </div> ); }
当前问题:初始渲染正常,输入the/会正确切换到TextField组件;但移除斜杠后,Autocomplete组件显示但输入内容为空,不符合预期。预期移除斜杠后应恢复输入the时的筛选列表状态。
复现步骤
- 运行项目
- 在Autocomplete中输入
the,显示筛选列表 - 输入
/,切换到TextField且内容为the/,此步骤正常 - 移除
/ - Autocomplete字段为空,出现问题
解决方案
问题原因
- 事件参数错误:
onchange函数定义了参数e,但内部使用全局event变量,导致Autocomplete触发onInputChange时无法正确获取输入值,进而让value状态更新错误。 - 输入值逻辑不兼容:TextField的
onChange仅传递事件对象,而Autocomplete的onInputChange传递事件对象和newValue,原代码未区分这两种场景的输入值获取方式。 - DOM聚焦方式不可靠:依赖
getElementById和setTimeout聚焦输入框,容易受DOM渲染时机影响,出现元素未挂载或id不匹配的情况。
修复后的代码
import React from 'react'; import TextField from '@mui/material/TextField'; import Autocomplete from '@mui/material/Autocomplete'; // 示例电影数据,根据实际情况替换 const top100Films = [ { label: 'The Shawshank Redemption', year: 1994 }, { label: 'The Godfather', year: 1972 }, { label: 'The Dark Knight', year: 2008 }, ]; export default function ComboBox() { const [showTextField, setShowTextField] = React.useState(false); const [inputValue, setInputValue] = React.useState(''); const autoCompleteInputRef = React.useRef(null); const textFieldInputRef = React.useRef(null); // 监听组件切换状态,自动聚焦对应输入框 React.useEffect(() => { if (showTextField) { textFieldInputRef.current?.focus(); } else { autoCompleteInputRef.current?.focus(); } }, [showTextField]); const handleInputChange = (e, newValue) => { // 兼容两种组件的输入值获取逻辑 const value = newValue !== undefined ? newValue : e.target.value; setInputValue(value); // 判断是否切换到TextField const shouldShowTextField = value.includes('/'); setShowTextField(shouldShowTextField); }; return ( <div> {showTextField ? ( <TextField ref={textFieldInputRef} id="outlined-basic" label="Outlined" variant="outlined" value={inputValue} onChange={handleInputChange} /> ) : ( <Autocomplete disablePortal id="combo-box-demo" options={top100Films} inputValue={inputValue} onInputChange={handleInputChange} sx={{ width: 300 }} renderInput={(params) => ( <TextField {...params} label="Movie" inputProps={{ ...params.inputProps, ref: autoCompleteInputRef }} /> )} /> )} </div> ); }
修复说明
- 修正事件参数:将全局
event替换为函数参数e,确保正确获取事件对象中的输入值。 - 兼容输入值获取:根据
newValue是否存在,分别处理TextField和Autocomplete的输入值,保证inputValue状态更新准确。 - 使用Ref实现可靠聚焦:通过
useRef获取输入框元素,结合useEffect监听组件切换状态,在组件渲染完成后自动聚焦,避免依赖setTimeout和DOM查询。 - 优化变量命名:将
show改为showTextField,setvalue改为setInputValue,提升代码可读性和语义化。
内容的提问来源于stack exchange,提问作者user5711656
相关产品推荐
相关产品推荐

