[英]Annotating Custom React Hook With TypeScript
我有一个自定义的 React Hook,可以监视特定元素之外的点击。 它工作得很好,但我在一些地方无法让 TypeScript 满意。
应用程序.js
import { useRef, useCallback } from "react";
import useClick from "./useClick";
export default function App() {
const asideRef = useRef(null);
const handleStuff = useCallback(() => {
console.log("a click outside of the sidebar occurred.");
}, []);
useClick(asideRef, handleStuff);
return (
<div className="App">
<aside ref={asideRef}>
<nav>
<ul></ul>
</nav>
</aside>
</div>
);
}
使用Click.js
import React, { useEffect } from "react";
const useClick = (ref: React.MutableRefObject<HTMLElement>, cb: () => void) => {
useEffect(() => {
const checkClick = (e: React.MouseEvent): void => {
if (ref.current && !ref.current.contains(e.target as Node)) {
cb();
}
};
document.addEventListener("click", checkClick);
return () => {
document.removeEventListener("click", checkClick);
};
}, [ref, cb]);
};
export default useClick;
第一个问题区域是在App.js
,这里调用了useClick
钩子。 TypeScript 抱怨传递给useClick
的第一个参数并给出以下消息:
Argument of type 'MutableRefObject<null>' is not assignable to parameter of type 'MutableRefObject<HTMLElement>'.
Type 'null' is not assignable to type 'HTMLElement'.ts(2345)
我知道这与我将 ref 的初始值设置为 null 有关,并且useClick
中的 ref 参数被注释为React.MutableRefObject<HTMLElement>
。 我只是不知道如何解决它。
第二个问题区域是在useClick.js
,其中添加和删除了事件侦听器。 TypeScript 似乎对我的checkClick
函数有问题。 错误太长了,我别无选择,只能在下面展示它的照片。
如果有人对如何解决这两个问题有任何想法,那么 TypeScript 会很高兴,我们将不胜感激。
Hi Dan:我将从需要改变的地方开始,然后在下面解释原因。 (我还重命名了您的 TypeScript 文件扩展名以反映它们的内容。)
useClick.ts
前:
// ...
const useClick = (ref: React.MutableRefObject<HTMLElement>, cb: () => void) => {
useEffect(() => {
const checkClick = (e: React.MouseEvent): void => {
// ...
后:
// ...
const useClick = (ref: React.RefObject<HTMLElement>, cb: () => void) => {
useEffect(() => {
const checkClick = (e: MouseEvent): void => {
// ...
App.tsx
前:
export default function App() {
const asideRef = useRef(null);
后:
export default function App() {
const asideRef = useRef<HTMLElement>(null);
首先,让我们解决checkClick
函数:这个函数签名应该可以分配给lib.dom.d.ts
的EventListener
类型:
interface EventListener {
(evt: Event): void;
}
因为你的参数是React.MouseEvent
,它没有扩展原生的Event
类型,所以不兼容。 只需使用本机MouseEvent
类型,因为您正在将侦听器添加到文档(无论如何与 React 无关。)
接下来,让我们看看useClick
的函数签名:
在阅读本部分时,您可能希望参考useRef
的类型定义:
第一个参数是唯一需要更改的参数,它需要从MutableRefObject
更改为RefObject
。 它们之间的区别可能很微妙,但您可以阅读一些很棒的资源来了解更多关于它们的信息。 例如,这里有一个:
https://dev.to/wojciechmatuszewski/mutable-and-immutable-useref-semantics-with-react-typescript-30c9
在创建传递给 React 以用于元素引用的 ref 时,您应该提供null
作为useRef
(您所做的)的初始参数,并为其应保存的值类型提供泛型类型注释(在本例中)它是HTMLElement
)。 当为 DOM 元素使用 ref 时,React 希望你永远不会改变这个 ref,因为它是由 React 控制的,所以在这种情况下useRef
返回的类型只是一个RefObject
。 因此,这就是您应该用于useClick
的第一个参数的useClick
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.