手动设置当前电流时,useRef()挂钩应使用哪种打字稿类型?

JPo*_*ock 3 typescript reactjs react-hooks

我如何使用带有Typescript的React ref作为可变实例?当前属性似乎被键入为只读。

我正在使用React + Typescript开发一个库,该库与React不会渲染的输入字段进行交互。我想捕获对HTML元素的引用,然后将React事件绑定到它。

  const inputRef = useRef<HTMLInputElement>();
  const { elementId, handler } = props;

  // Bind change handler on mount/ unmount
  useEffect(() => {
    inputRef.current = document.getElementById(elementId);
    if (inputRef.current === null) {
      throw new Exception(`Input with ID attribute ${elementId} not found`);
    }
    handler(inputRef.current.value);

    const callback = debounce((e) => {
      eventHandler(e, handler);
    }, 200);

    inputRef.current.addEventListener('keypress', callback, true);

    return () => {
      inputRef.current.removeEventListener('keypress', callback, true);
    };
  });
Run Code Online (Sandbox Code Playgroud)

它生成编译器错误: semantic error TS2540: Cannot assign to 'current' because it is a read-only property.

我也尝试过const inputRef = useRef<{ current: HTMLInputElement }>();导致此编译器错误:

Type 'HTMLElement | null' is not assignable to type '{ current: HTMLInputElement; } | undefined'.

  Type 'null' is not assignable to type '{ current: HTMLInputElement; } | undefined'.
Run Code Online (Sandbox Code Playgroud)

Guc*_*cal 16

as钥匙。

您可以像这样使用它作为输入组件。

const inputRef = useRef<HTMLInputElement>();
Run Code Online (Sandbox Code Playgroud)


Lui*_*sus 10

我通过搜索如何在与oruseRef一起使用时使用 Typescript进行输入来解决这个问题。接受的答案帮助我解决了这个问题。setTimeoutsetInterval

你可以这样声明你的超时/间隔

const myTimeout = useRef<ReturnType<typeof setTimeout> | null>(null)
Run Code Online (Sandbox Code Playgroud)

要清除它并再次设置它,您可以照常进行:

const handleChange = () => {
  if (myTimeout.current) {
    clearTimeout(myTimeout.current)
  }
  myTimeout.current = setTimeout(() => {
    doSomething()
  }, 500)
}
Run Code Online (Sandbox Code Playgroud)

如果您在 Node 中运行或在浏览器中运行,则键入将有效。


Ret*_*sam 6

是的,这是有关打字方式的古怪之处:

function useRef<T>(initialValue: T): MutableRefObject<T>;
function useRef<T>(initialValue: T|null): RefObject<T>;
Run Code Online (Sandbox Code Playgroud)

如果初始值包括null,但指定的类型参数不包括,则将其视为不可变的RefObject

这样做时useRef<HTMLInputElement>(null),您会遇到这种情况,因为T指定为HTMLInputElement,并且null推断为HTMLInputElement | null

您可以通过以下方法解决此问题:

useRef<HTMLInputElement | null>(null)
Run Code Online (Sandbox Code Playgroud)

然后THTMLInputElement | null,它与第一个参数的类型匹配,因此您点击了第一个替代并获得了一个可变的ref。

  • 谢谢你!这很有意义,并且可以编译我的代码。我使用了 `const inputRef = useRef&lt;HTMLElement | null&gt;(null);` 以避免来自 `inputRef.current = document.getElementById(elementId);` 的编译器错误 不确定这是否值得编辑。 (2认同)
  • 是的,如果您不需要引用中的任何特定于输入的属性,那么我会做您所做的事情并扩大您注释引用的类型;如果您确实需要特定于输入的属性,我可能会在分配之前执行 `getElementById(elementId) as HTMLInputElement` 。 (2认同)
  • @AmbroiseRabier你已经明确地将`shaderMat`注释为`RefObject`,这是不可变类型,所以是的,它不会让你在useEffect中改变它。您需要使用“useRef”的类型参数来控制类型,而不是变量本身的注释。 (2认同)