Yeh*_*ira 17 typescript reactjs react-typescript
在我正在开发的 React 代码库中,我有一个自定义钩子,它接受 RefObject 作为参数,以及与此类钩子一起使用的随附提供程序:
export const ScrollUtilsProvider = React.forwardRef<HTMLDivElement, ScrollUtilsProviderProps>(
(props, ref) => {
const scrollUtils = useScrollUtils(ref) // issue happens on this line
return <div ref={ref}><ScrollUtilsContext.Provider value={scrollUtils}>{props.children}</ScrollUtilsContext.Provider></div>
},
)
export const useScrollUtils = <T extends Element>(ref: RefObject<T>) => {
return {
// some cool functions w/ the passed ref
}
}
Run Code Online (Sandbox Code Playgroud)
我收到的错误消息:
Argument of type 'ForwardedRef<HTMLDivElement>' is not assignable to parameter of type 'RefObject<HTMLDivElement>'.
Type 'null' is not assignable to type 'RefObject<HTMLDivElement>'.
Run Code Online (Sandbox Code Playgroud)
深入研究这两种类型,我意识到它们确实不同:
Argument of type 'ForwardedRef<HTMLDivElement>' is not assignable to parameter of type 'RefObject<HTMLDivElement>'.
Type 'null' is not assignable to type 'RefObject<HTMLDivElement>'.
Run Code Online (Sandbox Code Playgroud)
我的问题是:
rpa*_*tel 29
interface RefObject<T> {
readonly current: T | null;
}
Run Code Online (Sandbox Code Playgroud)
RefObject
是方法的返回类型React.createRef
。
调用此方法时,它会返回一个对象,其唯一字段.current
设置为null
。不久之后,当 arender
将 ref 传递给组件时,React 将设置.current
为对该组件的引用。该组件通常是 DOM 元素(如果传递给 HTML 元素)或类组件的实例(如果传递给自定义类组件)。
请注意,RefObject
与 非常相似MutableRefObject<T | null>
,但.current
是readonly
。此类型规范仅用于指示该.current
属性由 React 内部管理,不应由 React 应用程序中的代码修改。
interface MutableRefObject<T> {
current: T;
}
Run Code Online (Sandbox Code Playgroud)
MutableRefObject
是方法的返回类型React.useRef
。在内部,React.useRef
创建 a MutableRefObject
,将其存储到功能组件的状态,然后返回该对象。
请注意,当对象存储到 React 组件的状态时,修改其属性不会触发重新渲染(因为 Javascript 对象是引用类型)。这种情况允许您在没有实例的功能组件中模仿类实例变量。换句话说,您可以将其视为React.useRef
一种将变量与功能组件关联起来而不影响组件渲染的方法。
React.useRef
下面是使用实例变量的类组件和用于实现相同目的的函数组件的示例:
class ClassTimer extends React.Component {
interval: NodeJS.Timer | null = null;
componentDidMount() {
this.interval = setInterval(() => { /* ... */ });
}
componentWillUnmount() {
if (!this.interval) return;
clearInterval(this.interval);
}
/* ... */
}
function FunctionalTimer() {
const intervalRef = React.useRef<NodeJS.Timer>(null);
React.useEffect(() => {
intervalRef.current = setInterval(() => { /* ... */ });
return () => {
if (!intervalRef.current) return;
clearInterval(intervalRef.current);
};
}, []);
/* ... */
}
Run Code Online (Sandbox Code Playgroud)
type ForwardedRef<T> =
| ((instance: T | null) => void)
| MutableRefObject<T | null>
| null;
Run Code Online (Sandbox Code Playgroud)
ForwardedRef
是 React 使用 传递给功能组件的 ref 类型React.forwardRef
。
这里的主要思想是父组件可以将 ref 传递给子组件。例如,MyForm
可以将 ref 转发到MyTextInput
,允许前者访问后者.value
呈现的HTMLInputElement
。
分解联合类型:
MutableRefObject<T | null>
- 转发的参考是使用 创建的React.useRef
。
((instance: T | null) => void)
- 转发的 ref 是回调 ref。
null
- 没有转发任何裁判。
当子组件接收到 时ForwardedRef
,通常会将 ref 暴露给父组件。但是,有时子组件可能需要使用 ref 本身。在这种情况下,您可以使用挂钩来协调ForwardedRef
上面列出的每种类型。
这是本文中的一个钩子(针对 Typescript 进行了调整),可以帮助实现这一目标:
function useForwardedRef<T>(ref: React.ForwardedRef<T>) {
const innerRef = React.useRef<T>(null);
React.useEffect(() => {
if (!ref) return;
if (typeof ref === 'function') {
ref(innerRef.current);
} else {
ref.current = innerRef.current;
}
});
return innerRef;
}
Run Code Online (Sandbox Code Playgroud)
这个钩子背后的想法是组件可以创建自己的引用,无论父组件是否转发引用,它都可以使用该引用。该钩子有助于确保任何转发的引用的.current
属性与内部的属性保持同步。
该钩子的返回类型是MutableRefObject<T>
,它应该与RefObject<T>
代码片段中的参数兼容useScrollUtils
,例如:
const MyComponent = React.forwardRef<HTMLDivElement>(
function MyComponent(_props, ref) {
const innerRef = useForwardedRef(ref);
useScrollUtils(innerRef);
return <div ref={innerRef}></div>;
}
);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
7962 次 |
最近记录: |