React Autocomplete组件useRef类型不匹配报错求助
问题描述
我在使用react-autocomplete组件的ref属性时遇到了如下TypeScript错误,搞不懂为啥不能直接用React useRef,求帮忙解答。
错误信息
No overload matches this call.
Overload 1 of 2, '(props: Props | Readonly): Autocomplete', gave the following error.
Type 'MutableRefObject' is not assignable to type 'LegacyRef | undefined'.
Type 'MutableRefObject' is not assignable to type 'RefObject '.
Types of property 'current' are incompatible.
Type 'undefined' is not assignable to type 'Autocomplete | null'.
Overload 2 of 2, '(props: Props, context: any): Autocomplete', gave the following error.
Type 'MutableRefObject' is not assignable to type 'LegacyRef | undefined'.ts(2769)
代码示例
const Search = () => { const [searchValue, setSearchValue] = useState(''); const [isOpened, setIsOpened] = useState(false); const inputRef = useRef<HTMLInputElement>(null); const handleButtonOnClick = () => { setSearchValue(''); setIsOpened(false); inputRef.current.focus(); }; const handleOnSelect = (val: string, item: any) => { setSearchValue(val); setIsOpened(false); console.info('test'); console.log(item); }; const handleOnChange: React.ChangeEventHandler<HTMLInputElement> = ( e: React.ChangeEvent<HTMLInputElement> ) => { setSearchValue(e.target.value); setIsOpened(true); }; return ( <> <Autocomplete getItemValue={item => item.description} renderMenu={(items, value) => ( <div>{items.length === 0 ? `No matches for ${value}` : items}</div> )} shouldItemRender={(item, value) => item.description.toLowerCase().indexOf(value.toLowerCase()) > -1 } items={data.Sheet} renderItem={(item, isHighlighted) => ( <div style={{ background: isHighlighted ? 'lightgray' : 'white' }}> {item.description} </div> )} autoHighlight={false} value={searchValue} onChange={e => handleOnChange(e)} onSelect={(val, item) => handleOnSelect(val, item)} open={isOpened} ref={inputRef} /> <Button value="clear" onClick={handleButtonOnClick}></Button> </> ); };
错误原因与解决方案
为啥报错?
你踩了两个关键坑:
- 类型不匹配:
Autocomplete组件的ref要求指向组件实例(Autocomplete类型),但你定义的inputRef是HTMLInputElement类型,TypeScript对类型校验严格,自然不兼容。 - 逻辑错配:你想获取的是Autocomplete内部的input元素,但直接给组件传ref只能拿到组件本身,拿不到内部DOM节点。
怎么解决?
分两种场景处理:
场景1:要操作内部的input元素(比如调用focus)
大部分Autocomplete组件支持通过inputProps把属性传递给内部input元素,包括ref:
const Search = () => { const [searchValue, setSearchValue] = useState(''); const [isOpened, setIsOpened] = useState(false); const inputRef = useRef<HTMLInputElement>(null); // 其他逻辑保持不变 return ( <> <Autocomplete // 保留所有原有props getItemValue={item => item.description} renderMenu={(items, value) => ( <div>{items.length === 0 ? `No matches for ${value}` : items}</div> )} shouldItemRender={(item, value) => item.description.toLowerCase().indexOf(value.toLowerCase()) > -1 } items={data.Sheet} renderItem={(item, isHighlighted) => ( <div style={{ background: isHighlighted ? 'lightgray' : 'white' }}> {item.description} </div> )} autoHighlight={false} value={searchValue} onChange={e => handleOnChange(e)} onSelect={(val, item) => handleOnSelect(val, item)} open={isOpened} // 关键:通过inputProps传递ref给内部input inputProps={{ ref: inputRef }} /> <Button value="clear" onClick={handleButtonOnClick}></Button> </> ); };
场景2:需要操作Autocomplete组件本身的实例
如果你确实要调用组件自身的方法,把ref的类型改成Autocomplete即可:
// 先确保导入了Autocomplete的类型 import { Autocomplete } from 'react-autocomplete'; const Search = () => { const [searchValue, setSearchValue] = useState(''); const [isOpened, setIsOpened] = useState(false); // 把ref类型改为Autocomplete const autocompleteRef = useRef<Autocomplete>(null); // 示例:调用组件的某个方法 const handleReset = () => { autocompleteRef.current?.reset(); // 假设组件有reset方法 }; return ( <> <Autocomplete // 所有原有props不变 getItemValue={item => item.description} renderMenu={(items, value) => ( <div>{items.length === 0 ? `No matches for ${value}` : items}</div> )} shouldItemRender={(item, value) => item.description.toLowerCase().indexOf(value.toLowerCase()) > -1 } items={data.Sheet} renderItem={(item, isHighlighted) => ( <div style={{ background: isHighlighted ? 'lightgray' : 'white' }}> {item.description} </div> )} autoHighlight={false} value={searchValue} onChange={e => handleOnChange(e)} onSelect={(val, item) => handleOnSelect(val, item)} open={isOpened} // 此时ref类型匹配 ref={autocompleteRef} /> <Button value="clear" onClick={handleButtonOnClick}></Button> <Button onClick={handleReset}>Reset</Button> </> ); };
核心要点
- 给组件传ref时,ref的类型必须和组件实例类型一致,不能把DOM元素类型的ref传给组件。
- 要操作组件内部DOM元素,优先用组件提供的API(比如
inputProps)传递ref,别直接给组件传DOM类型的ref。
内容的提问来源于stack exchange,提问作者Kiwimoisi

