使用 useRef 在 Reactjs 中从父级调用子函数

Call Child Function from Parent in Reactjs using useRef

代码是使用 React 函数式组件编写的。

单击父项中的按钮后,应触发函数 showAlert。就是这个要求。

目前在父组件childRef.current中无法调用showAlert()函数。我收到打字稿错误

Property 'showAlert' does not exist on type 'ForwardRefExoticComponent<RefAttributes<unknown>>'

父功能组件代码

import React, { forwardRef, useRef, useImperativeHandle } from 'react';
import Child from './Child';
export default function App() {
  const childRef = useRef<typeof Child>(Child);
  return (
    <div className="container">

      <Child ref={childRef} />
      <button
        onClick={() => { childRef.current.showAlert() }}
      >
        Call Function
            </button>
      
    </div>
  )
}

子功能组件

import React, { forwardRef, useRef, useImperativeHandle } from 'react';

const Child = forwardRef((props, ref) => {
    useImperativeHandle(
        ref,
        () => ({
             showAlert() {
                alert("Child Function Called")
                console.log('hello world')
            }
        }),
    )
    return (
        <div>Child Component</div>
    )
})

export default Child

试试这个方法

useImperativeHandle(
        ref,
        () => ({
             showAlert: () => { // like this here
                alert("Child Function Called")
                console.log('hello world')
            }
        }),
)

你几乎说对了,但是 typeof Child 没有给你一个准确的类型,因为 Child 组件本身的类型不够严格。它被推断为 forwardRef<unknown, {}>。我们需要指定转发 ref 的类型才能使其正常工作。

我们可以为我们想要的 ref 定义一个接口:

interface CanShowAlert {
  showAlert(): void;
}

我们在 ChildforwardRef 函数上设置了两个泛型。 CanShowAlert 是 ref 类型,{} 是 props 类型:

const Child = forwardRef<CanShowAlert, {}>((props, ref) => {

我们在 useRef:

上使用相同的泛型
const childRef = useRef<CanShowAlert>(null);

您的初始值 useRef<CanShowAlert>(Child) 出现错误,因为 ref 是针对组件的 实例 ,但您传入的是组件函数本身。相反,我们使用 null 作为初始值。

ref 的 current 属性 要么是一个组件实例,要么是 null,所以我们在调用之前需要确保它不是 null showAlert 函数。为此,我们可以使用可选的链接运算符 ?.

childRef.current?.showAlert()

完整代码:

import React, {forwardRef, useRef, useImperativeHandle} from "react";

interface CanShowAlert {
  showAlert(): void;
}

export default function App() {
  const childRef = useRef<CanShowAlert>(null);
  return (
    <div className="container">

      <Child ref={childRef} />
      <button
        onClick={() => { childRef.current?.showAlert() }}
      >
        Call Function
            </button>
      
    </div>
  )
}


const Child = forwardRef<CanShowAlert, {}>((props, ref) => {
    useImperativeHandle(
        ref,
        () => ({
             showAlert() {
                alert("Child Function Called")
                console.log('hello world')
            }
        }),
    )
    return (
        <div>Child Component</div>
    )
})