Material UI Autocomplete自定义Paper内输入框每输入一个字符失焦问题求解
问题根因
你当前遇到的输入框失焦问题核心原因是:你在Autocomplete的props中内联定义了PaperComponent函数。
每当你更新options、customFilterString等状态触发父组件重渲染时,这个内联定义的PaperComponent会生成全新的函数引用,React会判定这是一个全新的组件类型,直接卸载旧的Paper实例并重新挂载新实例,内部的自定义输入框也会随之销毁重建,自然就会丢失焦点。
可行解决方案
方案1:稳定PaperComponent的引用
不要内联定义PaperComponent,根据你的使用场景可以二选一:
- 如果自定义Paper不需要用到Autocomplete所在组件的内部状态,直接把PaperComponent定义移到组件外部,全局只声明一次即可。
- 如果需要用到内部状态(比如customFilterString、closeOptionsList等),用
useMemo包裹PaperComponent的定义,保证仅在依赖项变化时才更新引用:
// 在Autocomplete所在的组件内部声明 const MemoizedPaperComponent = useMemo(() => { return ({children, ...other}) => ( <Paper {...other}> <ClickAwayListener onClickAway={closeOptionsList}> <div key="click-away-wrapper"> <Input styleInput={{width: '100%'}} value={customFilterString} onChange={handleCustomFilterChange} className="slds-m-horizontal_small slds-m-top_small" iconRight={<InputIcon name="search" category="utility" />} /> {children} </div> </ClickAwayListener> </Paper> ) // 依赖项仅包含你用到的内部变量即可 }, [closeOptionsList, customFilterString, handleCustomFilterChange]) // Autocomplete props处引用 <Autocomplete PaperComponent={MemoizedPaperComponent} // 其他props保持不变 />
方案2:调整搜索框放置位置
如果不想修改Paper的定义,也可以换更符合MUI Autocomplete渲染逻辑的放置位置:
- 用
ListboxComponent属性自定义选项列表容器,把搜索框放在选项列表的顶部 - 或者自定义
PopperComponent,把搜索框嵌入到弹出层的最上方,完全避开Paper的重渲染逻辑影响
额外排查点
检查ClickAwayListener的onClickAway逻辑,避免输入框输入时误触发关闭逻辑,也可能连带导致焦点丢失。可以在关闭前增加判断,仅当点击源不在输入框和选项列表内部时再执行关闭。
内容的提问来源于stack exchange,提问作者Tyler Dahle
相关产品推荐
相关产品推荐

