React+MUI Autocomplete二次打开无选项且持续加载问题
问题解决:Material-UI Autocomplete 关闭后重开无选项且加载持续的问题
问题根源
代码里两个核心逻辑错误导致了该现象:
App组件中存在一个useEffect,在下拉框关闭(open变为false)时执行setOptions([])清空选项,导致再次打开时options为空;- 打开下拉框时未重新触发数据获取,而原
loading判断逻辑const loading = open && options.length === 0会持续为true,因为没有新请求填充选项。
同时还需要补充实现无搜索结果时的提示功能。
修复后的完整代码
Auto.tsx
import * as React from "react"; import { Autocomplete, TextField, Typography } from "@mui/material"; import SearchIcon from "@material-ui/icons/Search"; import InputAdornment from "@material-ui/core/InputAdornment"; import CircularProgress from "@material-ui/core/CircularProgress"; interface Option { label: string; value: number; } interface IProps { fetchServerSideOptions?: (inputValue: string) => void; loading?: boolean; open?: boolean; onOpen?: (event: React.SyntheticEvent) => void; onClose?: (event: React.SyntheticEvent, reason: string) => void; options: Option[]; selected: Option | null; setSelected: React.Dispatch<React.SetStateAction<Option | null>>; } export default function Auto(props: IProps) { const { options = [], selected, setSelected, open, loading, onOpen, onClose, fetchServerSideOptions } = props; return ( <Autocomplete forcePopupIcon={false} options={options} value={selected} open={open} loading={loading} onOpen={onOpen} onClose={onClose} onChange={(_event, value) => setSelected(value)} onInputChange={(_event, value) => fetchServerSideOptions?.(value)} renderOption={(props, option) => ( <li {...props}> <Typography>{option.label}</Typography> </li> )} noOptionsText={ loading ? <CircularProgress size={20} /> : "无匹配选项" } renderInput={(params) => { return ( <TextField {...params} placeholder="Select" InputProps={{ ...params.InputProps, startAdornment: ( <React.Fragment> <InputAdornment position="start"> <SearchIcon /> </InputAdornment> {params.InputProps.startAdornment} </React.Fragment> ), endAdornment: ( <React.Fragment> {loading ? ( <CircularProgress color="inherit" size={20} /> ) : null} {params.InputProps.endAdornment} </React.Fragment> ) }} /> ); }} /> ); }
App.tsx
import { useState, useEffect } from "react"; import Auto from "./Auto"; interface Option { label: string; value: number; } export default function App() { const [options, setOptions] = useState<Option[]>([]); const [selected, setSelected] = useState<Option | null>(null); const [open, setOpen] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false); const [currentInput, setCurrentInput] = useState<string>(""); const fetchOptions = async (value: string) => { setLoading(true); try { const response: Response = await fetch( `https://dummyjson.com/products/search?q=${value}&limit=10` ); const { products } = await response.json(); const formattedOptions = products.map(({ title, id }) => { return { label: title, value: id }; }); setOptions(formattedOptions); } catch (err) { console.error("请求失败:", err); setOptions([]); } finally { setLoading(false); } }; useEffect(() => { fetchOptions(""); }, []); useEffect(() => { if (open && options.length === 0) { fetchOptions(currentInput); } }, [open, currentInput, options.length]); return ( <Auto selected={selected} setSelected={setSelected} options={options} open={open} loading={loading} onOpen={() => setOpen(true)} onClose={() => setOpen(false)} fetchServerSideOptions={(value) => { setCurrentInput(value); fetchOptions(value); }} /> ); }
关键修复点
- 移除关闭下拉框清空选项的逻辑:原逻辑导致再次打开时无初始数据,直接触发加载状态;
- 独立管理loading状态:不再依赖
open和options长度判断加载,改为请求开始/结束时手动控制,避免逻辑冲突; - 添加打开下拉框的重新请求逻辑:当下拉框打开且无选项时,根据当前输入值重新获取数据;
- 实现无结果提示:利用
Autocomplete的noOptionsText属性,非加载状态下显示“无匹配选项”; - 修复类型不匹配:统一
selected属性的类型为Option | null,保证父子组件类型一致。
内容的提问来源于stack exchange,提问作者lrr59
相关产品推荐
相关产品推荐

