在 React 自定义钩子中正确输入 useRef 值
Posted
技术标签:
【中文标题】在 React 自定义钩子中正确输入 useRef 值【英文标题】:Properly typing useRef values in a React custom hook 【发布时间】: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
【参考方案1】:
这是因为 ref 的值存储在“.current”属性下。
即
const Comp = () =>
...
const refVal = React.useRef(2);
console.log(2 === refVal); // false
console.log(2 === refVal.current); // true
...
解决方案取决于您的意图 - 如果您想返回 ref 本身,请按照类型错误的建议将接口的类型更改为 MutableRefObject<HTMLElement | null>
,否则,将返回值替换为:
return
someBooleanState,
myRef: myRef.current,
如果 el 尚未定义(即尚未分配),您可能会收到 undefined
s,因为您使用 ?.
运算符访问属性(需要明确的是,这是正确的。
例如
null?.test === undefined; // true
要解决这个问题,请检查 el 是否已定义且可选(尽管接口的定义并不要求这样做),检查两个值是否已定义且均为数字(即使用 el && !isNaN(el?.offsetWidth) && !isNaN(el?.scrollWidth) && el.offsetWidth < el.scrollWidth
。或者,使用 nullish 合并运算符 if这适用于您的用例,即(el?.offsetWidth ?? 0) < (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?.offsetWidth
是undefined
,因为el
仍然是null
。而undefined
不是<
比较中的有效操作数。 (if (undefined < 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
上进行数学运算。以上是关于在 React 自定义钩子中正确输入 useRef 值的主要内容,如果未能解决你的问题,请参考以下文章