在 React 自定义挂钩中正确输入 useRef 值

Properly typing useRef values in a React custom hook

我有一个自定义挂钩,在我的 TS 应用程序中 returns 值为 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
    }
  }
  

正如您在评论中看到的,我的钩子有一些与输入相关的错误:

1- 不知道如何在界面中输入 myRef。请记住,它将用于多种类型的 HTML 元素,因此我无法在此处指定它是 div 还是什么。

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

如何在挂钩中正确输入这些值?

发生这种情况是因为 ref 的值存储在“.current”下 属性。

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

解决方案取决于您的意图 - 如果您想要 return ref 本身,请按照类型错误的建议将接口类型更改为 MutableRefObject<HTMLElement | null>,否则,替换 return 值:

    return {
        someBooleanState,
        myRef: myRef.current,
    }

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

例如

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

要解决这个问题,请检查 el 是否已定义并且可选(尽管接口定义不需要),检查两个值是否已定义并且都是数字(即使用 el && !isNaN(el?.offsetWidth) && !isNaN(el?.scrollWidth) && el.offsetWidth < el.scrollWidth。或者,使用如果这适用于您的用例,则无效合并运算符,即 (el?.offsetWidth ?? 0) < (el?.scrollWidth ?? 0).

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

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

React.MutableRefObject<HTMLElement | null>

这让你的钩子 return 输入:

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 仍然是 nullundefined 不是 < 比较中的有效操作数。 (if (undefined < undefined)没有多大意义)

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

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

Working example