React中Material UI Autocomplete新增分类后切换焦点内容消失问题
解决Material UI Autocomplete焦点切换后内容消失问题
问题描述
我在React应用中使用Material UI的Autocomplete组件实现分类的添加与删除,添加分类通过Dialog弹窗完成。目前点击Dialog确认按钮后,分类能成功存入数据库,且分类名称会显示在Autocomplete输入框中,但按下Tab键切换到表单下一个输入框时,Autocomplete输入框中的内容会消失,需要解决这个焦点切换后内容保留的问题。
问题原因分析
- 错误的状态更新逻辑:在
handleAddCategory函数中,先设置autocompleteInput为新分类名称,随后又错误地将其设置为newCategoryName.value(此时newCategoryName已被清空),导致输入框内容被重置。 - 不严谨的useEffect监听:每次
categories数组更新(包括删除分类操作)都会触发useEffect,强制将autocompleteInput设置为最后一个分类名称,覆盖用户输入。 - 未绑定Autocomplete的value属性:仅绑定
inputValue会导致组件无法正确识别选中的选项,焦点切换时可能触发输入框清空。
解决方案
- 修复
handleAddCategory中的状态更新逻辑,移除错误的状态赋值。 - 添加状态标记区分分类添加操作,优化
useEffect的触发条件。 - 为Autocomplete绑定
value属性,同步选中的选项状态。
修改后的完整代码
function EnterForm() { const [input, setInput] = useState({ amount: "", category: "", comment: "", date: "", }); const [categories, setCategories] = useState([]); const [openDialog, setOpenDialog] = useState(false); const [newCategoryName, setNewCategoryName] = useState(""); const [autocompleteInput, setAutocompleteInput] = useState(""); const [alertOpen, setAlertOpen] = useState(false); const [isAddingCategory, setIsAddingCategory] = useState(false); // 标记是否正在添加分类 const getTransactions = async () => { await axios .get("http://localhost:3001/read") .then((res) => setCategories(res.data)) .catch((err) => console.log(err)); }; const getCategory = async () => { await axios.get("http://localhost:3001/readCategory") .then((res) => setCategories(res.data)) .catch((err) => console.log(err)); } useEffect(() => { getTransactions(); getCategory(); }, []); useEffect(() => { // 仅在添加分类时自动填充输入框 if (categories.length > 0 && isAddingCategory) { const lastCategory = categories[categories.length - 1]; setAutocompleteInput(lastCategory.autocomplete); setInput((prevInput) => ({ ...prevInput, category: lastCategory.autocomplete, })); setIsAddingCategory(false); // 重置标记 } }, [categories, isAddingCategory]); const handleOpenDialog = () => { setOpenDialog(true); setNewCategoryName(autocompleteInput); }; const handleCloseDialog = () => { setOpenDialog(false); }; const handleAddCategory = async (event) => { event.preventDefault(); const categoryToAdd = { autocomplete: newCategoryName }; try { const response = await axios.post("http://localhost:3001/newcategory", categoryToAdd); const newCategory = response.data; setCategories((prevCategories) => [...prevCategories, newCategory]); setNewCategoryName(""); // 正确设置输入框值 setAutocompleteInput(newCategory.autocomplete); handleCloseDialog(); setIsAddingCategory(true); // 设置添加标记 await getCategory(); } catch (err) { console.log(err); } }; const handleClose = (event, reason) => { if (reason === 'clickaway') { return; } setAlertOpen(false); }; // 找到当前选中的分类选项 const selectedCategory = categories.find( cat => cat.autocomplete === input.category ); return ( <Grid container sx={{ margin: "5%" }} spacing={2} alignItems="center"> <Grid item xs={12}> <Typography variant="h4" sx={{ margin: 1 }}> Introdu tranzactie: </Typography> </Grid> <Grid item xs={12}> <div style={{ width: "50%", margin: 5, textAlign: "left" }}> <Autocomplete fullWidth getOptionLabel={(option) => option.autocomplete} options={categories} inputValue={autocompleteInput} value={selectedCategory} // 绑定选中的选项值 onInputChange={(event, newInputValue) => setAutocompleteInput(newInputValue)} onChange={(event, value) => { setInput({ ...input, category: value ? value.autocomplete : "" }); // 同步inputValue setAutocompleteInput(value ? value.autocomplete : ""); }} isOptionEqualToValue={(option, value) => option._id === value._id} noOptionsText={ <Button onClick={handleOpenDialog}> Add new category </Button> } renderInput={(params) => <TextField {...params} label="Categorie" />} renderOption={(props, option) => ( <Box component="li" {...props} key={option._id}> {option.autocomplete} <IconButton style={{ color: "#c70000" }} sx={{ marginLeft: "auto" }} aria-label="delete" onClick={(event) => { event.stopPropagation(); handleDeleteCategory(option._id); }} > <DeleteIcon /> </IconButton> </Box> )} /> </div> </Grid> <Dialog open={openDialog} onClose={handleCloseDialog}> <DialogTitle>Add a New Category</DialogTitle> <DialogContent> <DialogContentText> To add a new category, please enter the category name here. </DialogContentText> <TextField autoFocus margin="dense" id="name" label="Category Name" type="text" fullWidth variant="standard" value={newCategoryName} onChange={(e) => setNewCategoryName(e.target.value)} /> </DialogContent> <DialogActions> <Button onClick={handleCloseDialog}>Cancel</Button> <Button onClick={handleAddCategory}>Add</Button> </DialogActions> </Dialog> </Grid> ); } export default EnterForm;
内容的提问来源于stack exchange,提问作者Victor Arodu
相关产品推荐
相关产品推荐

