我正在尝试使用
useRef
从父组件调用子组件方法。
将来,
SayHi
方法将更新子组件中的钩子状态。不幸的是,我有无法处理的错误。
线路:
ref.current.SayHi();
类型“ForwardRefExoticComponent<{ name: string; } & RefAttributes<{ SayHi: () => void”上不存在属性“SayHi”; }>>'。
线路:
<Child name="Adam" ref={ref}/>
输入“RefObject
void”; }>>>' 不可分配给类型 '((instance: { SayHi: () => void; } | null) => void) | RefObject<{ SayHi: () => 无效; }> |空 |不明确的'。 输入 'RefObject void; }>>>' 不可分配给类型 'RefObject<{ SayHi: () => void; }>'。 类型“ForwardRefExoticComponent<{ name: string; } & RefAttributes<{ SayHi: () => void”中缺少属性“SayHi”; }>>' 但在类型 '{ SayHi: () => void; 中是必需的}'.
完整
test.tsx
文件:
import React, { useRef, forwardRef, useImperativeHandle, Ref } from 'react'
const Parent = () => {
const ref = useRef<typeof Child>(null);
const onButtonClick = () => {
if (ref.current) {
ref.current.SayHi();
}
};
return (
<div>
<Child name="Adam" ref={ref}/>
<button onClick={onButtonClick}>Log console</button>
</div>
);
}
const Child = forwardRef((props: {name: string}, ref: Ref<{SayHi: () => void}>)=> {
const {name} = props;
useImperativeHandle(ref, () => ({ SayHi }));
function SayHi() { console.log("Hello " + name); }
return <div>{name}</div>;
});
我在这个话题上深深寻求帮助。
您需要在其他地方提取引用类型:
interface RefObject {
SayHi: () => void
}
然后在两个地方引用即可
const Child = forwardRef((props: {name: string}, ref: Ref<RefObject>)=> {
const {name} = props;
useImperativeHandle(ref, () => ({ SayHi }));
function SayHi() { console.log("Hello " + name); }
return <div>{name}</div>;
});
const Parent = () => {
const ref = useRef<RefObject>(null);
const onButtonClick = () => {
if (ref.current) {
ref.current.SayHi();
}
};
return (
<div>
<Child name="Adam" ref={ref}/>
<button onClick={onButtonClick}>Log console</button>
</div>
);
}
只需将您的
ref
的声明替换为这个 const ref = useRef<{ SayHi: () => void }>(null);
useRef<typeof SomeForwardRefComponent>
的问题是,它认为ref.current将获得forwardRef
返回的对象类型。然后它期望诸如 ref.current.displayName
而不是 ref.current.focus()
等属性。
您可以使用React的
ElementRef
类型工具提取传递给forwardRef的ref参数的类型,例如useRef<ElementRef<typeof Child>>
:
import React, { type ElementRef, type Ref, forwardRef, useRef } from 'react'
const Child = forwardRef<SomeElementType, Props>((props, ref) => (
/* ...render something */
)
// ...or (same thing but with slightly different syntax where you specify ref type):
const Child = forwardRef((props: Props, ref: Ref<SomeElementType>) => (
/* ...render something */
)
const Parent = () => {
// ref here has the same type as if you did useRef<SomeElementType>
const ref = useRef<ElementRef<typeof Child>>(null)
return (
<Child ref={ref} ... />
)
}
这可行,但是
ElementRef<typeof Child>
有点啰嗦。它基本上只是作为类型参数传递给 forwardRef
的任何内容的复杂别名。
如果您从不受控制的库导入
forwardRef
ed 组件,这可能是最好的解决方案,但如果您控制父级和子级的代码,则最好只定义 ref 类型然后导出和导入它。例如:
// In `child.tsx`
import React, { forwardRef } from 'react'
export type ChildRefType = SomeElementType
export type ChildProps = { ... }
export const Child = forwardRef<ChildRefType, ChildProps>((props, ref) => (
/* render something */
))
// In `parent.tsx`
import React, { useRef } from 'react'
import { Child, ChildRefType } from './child'
export const Parent = () => {
// ref here has the same type as if you did useRef<SomeElementType>
const ref = useRef<ChildRefType>(null)
return (
<Child ref={ref} ... />
)
}