手动设置电流时,我在 useRef() 钩子上使用啥打字稿类型?

Posted

技术标签:

【中文标题】手动设置电流时,我在 useRef() 钩子上使用啥打字稿类型?【英文标题】:What typescript type do I use with useRef() hook when setting current manually?手动设置电流时,我在 useRef() 钩子上使用什么打字稿类型? 【发布时间】:2020-01-20 20:30:04 【问题描述】:

如何通过 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);
    ;
  );

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

我也试过const inputRef = useRef&lt; current: HTMLInputElement &gt;();这导致这个编译器错误:

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

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

【问题讨论】:

我认为HTMLInputElement是正确的,但是inputRef最初应该设置为nulluseRef&lt;HTMLInputElement(null) 我也是这么想的。如果 ref 在 React 的渲染期间被捕获 - &lt;input ref=myRef /&gt; - 没有设置 myRef.current = ... 这可能会有所帮助:github.com/DefinitelyTyped/DefinitelyTyped/issues/… 特别是 ref7 【参考方案1】:

是的,这是打字方式的一个怪癖:

function useRef<T>(initialValue: T): MutableRefObject<T>;
function useRef<T>(initialValue: T|null): RefObject<T>;

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

当您执行useRef&lt;HTMLInputElement&gt;(null) 时,您遇到了这种情况,因为T 被指定为HTMLInputElement,而null 被推断为HTMLInputElement | null

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

useRef<HTMLInputElement | null>(null)

那么THTMLInputElement | null,它与第一个参数的类型相匹配,因此您点击第一个覆盖并获得一个可变引用。

【讨论】:

谢谢!这很有意义,并且可以编译我的代码。我使用const inputRef = useRef&lt;HTMLElement | null&gt;(null); 来避免来自inputRef.current = document.getElementById(elementId); 的编译器错误不知道这是否值得编辑。 是的,如果您不需要来自 ref 的任何特定于输入的属性,那么我会做您所做的并扩大您注释 ref 的类型;如果您确实需要特定于输入的属性,我可能会在分配之前执行getElementById(elementId) as HTMLInputElement 作为对其他任何人的参考,我发现如果没有 useRef 钩子就无法做到这一点, createRef 不允许这样做。也许有办法,但我找不到。 似乎不适用于变量(在 useEffect 中分配)const shaderMat: React.RefObject&lt;THREE.ShaderMaterial|null&gt; = useRef(null); 不允许我执行 shaderMat.current = mat;,因为 curretn 是只读的。 @AmbroiseRabier 您已将shaderMat 明确注释为RefObject,这是不可变类型,所以是的,它不会让您在useEffect 中对其进行变异。您需要使用useRef 的类型参数来控制类型,而不是变量本身的注释。

以上是关于手动设置电流时,我在 useRef() 钩子上使用啥打字稿类型?的主要内容,如果未能解决你的问题,请参考以下文章

[使用useref钩子将鼠标悬停在具有React的卡上

我如何在 reactjs + typescript (钩子)中使用 useRef 将子状态值传递给父级

如何将 React useRef 钩子与打字稿一起使用?

useRef() 无效的钩子调用 [NextJs]

useRef 反应钩子

使用redux-form按下下一个键盘按钮后如何使用useRef钩子选择下一个TextInput