You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Autocomplete组件useRef类型不匹配报错求助

解决react-autocomplete组件的TypeScript ref类型错误

问题描述

我在使用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>
    </>
  );
};

错误原因与解决方案

为啥报错?

你踩了两个关键坑:

  1. 类型不匹配:Autocomplete组件的ref要求指向组件实例(Autocomplete类型),但你定义的inputRef是HTMLInputElement类型,TypeScript对类型校验严格,自然不兼容。
  2. 逻辑错配:你想获取的是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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 16:37:53