【问题标题】:Properly typing useRef values in a React custom hook在 React 自定义钩子中正确输入 useRef 值
【发布时间】:2021-06-29 20:45:51
【问题描述】:

我有一个自定义钩子,它在我的 TS 应用程序中返回值 useRef。不幸的是,它抱怨我返回的 ref 的类型,我不知道如何正确输入。

这就是我的钩子的样子:


interface MyHookInterface {
    someBooleanState: boolean
    myRef: HTMLElement | null
}

  
const useMyHook = (): MyHookInterface => {
    const [someBooleanState, setSomeBooleanState] = useState<boolean>(false)
    const myRef = useRef<HTMLElement | null>(null)
  
    useEffect(() => {
      const el = myRef.current // what type should this be?
      // Complaining that el possibly undefined 
      if(el?.offsetWidth < el?.scrollWidth){
          // do stuff
      }
    }, [])
  
    return {
        someBooleanState,
        myRef, // Getting: Type 'MutableRefObject<HTMLElement | null>' is missing the following properties from type 'HTMLElement': accessKey, accessKeyLabel, autocapitalize, dir, and 234 more
    }
  }
  

正如您在 cmets 中看到的,我的钩子有一些与打字有关的错误:

1- 不知道如何在界面中输入myRef。请记住,它是用于多种类型的 HTML 元素,所以我不能在这里指定它是 div 还是什么。

2- 不知道如何输入el,但对其属性的访问抱怨它是undefined

如何在我的钩子中正确键入这些值?

【问题讨论】:

  • 在您的界面中,您将 myRef 的返回类型指定为 HTMLELement,但在 useMyHook 中您将返回 Ref 对象。你应该返回{ myRef: myRef.current }

标签: reactjs typescript react-hooks use-ref


【解决方案1】:

这是因为 ref 的值存储在“.current”属性下。

const Comp = () => {
...
    const refVal = React.useRef(2);
    console.log(2 === refVal); // false
    console.log(2 === refVal.current); // true
...
}

解决方案取决于您的意图 - 如果您想返回 ref 本身,请按照类型错误的建议将接口的类​​型更改为 MutableRefObject&lt;HTMLElement | null&gt;,否则,将返回值替换为:

    return {
        someBooleanState,
        myRef: myRef.current,
    }

如果 el 尚未定义(即尚未分配),您可能会收到 undefineds,因为您使用 ?. 运算符访问属性(需要明确的是,这是正确的。

例如

null?.test === undefined; // true

要解决这个问题,请检查 el 是否已定义且可选(尽管接口的定义并不要求这样做),检查两个值是否已定义且均为数字(即使用 el &amp;&amp; !isNaN(el?.offsetWidth) &amp;&amp; !isNaN(el?.scrollWidth) &amp;&amp; el.offsetWidth &lt; el.scrollWidth。或者,使用 nullish 合并运算符 if这适用于您的用例,即(el?.offsetWidth ?? 0) &lt; (el?.scrollWidth ?? 0)

【讨论】:

    【解决方案2】:

    ref 的类型不仅仅是它所引用的对象。这是一个React.MutableRefObject,它包含了它所引用的内容。这就是提供 current 属性的原因,因此 ref 可以工作。

    如果您仔细考虑myRef,您应该会看到您需要的类型。在这种情况下:

    React.MutableRefObject<HTMLElement | null>
    

    这会让你的钩子返回如下类型:

    interface MyHookInterface {
        someBooleanState: boolean
        myRef: React.MutableRefObject<HTMLElement | null>
    }
    

    其次,这个不起作用的原因:

      const el = myRef.current // what type should this be?
      
      // Complaining that el possibly undefined 
      if(el?.offsetWidth < el?.scrollWidth){
          // do stuff
      }
    

    是因为你的 ref 可能还没有被赋值。这意味着el?.offsetWidthundefined,因为el 仍然是null。而undefined 不是&lt; 比较中的有效操作数。 (if (undefined &lt; undefined) 没有多大意义)

    您可以通过在进行比较之前检查以确保 el 存在来轻松解决此问题:

      if (el && el.offsetWidth < el.scrollWidth){
          // do stuff
      }
    

    Working example

    【讨论】:

    • 关于 Object possibly undefined 警告,我认为可选的链接运算符 (?.) 会解决这个问题。不过没关系,我可以做检查。否则,一切都好!
    • 正如我在上面的答案中添加的那样,?。运算符是警告的原因,而不是解决方案 - 如果 el 为 null / undefined,它确实会返回 undefined - 即null?.test === undefined
    • @theJuls ?. 是一个非常方便的操作符,但它并不总是适合所有情况。在这种情况下,它确实可以让您安全地访问可能是 null 对象的属性。但是,它不允许您在 undefined 上进行数学运算。
    猜你喜欢
    • 2021-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-26
    • 2020-03-07
    • 2020-08-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多