ref 的作用是获取实例,但由于函数组件不存在实例,因此无法通过 ref 获取函数组件的实例引用

<Child ref={componentRef}></Child>
// 不能将类型“{ ref: MutableRefObject<undefined>; }”分配给类型“IntrinsicAttributes”。
// 类型“IntrinsicAttributes”上不存在属性“ref”。ts(2322)

使用 React.forwardRef() 引用子组件

ReactForwardRef 创建一个 React 组件,该组件能够将其接收的 ref 属性转发到自己的组件树,返回一个对象类型

React.forwardRef((props, ref) => {
	return (
	
	)
})

// ref - 父组件接收子组件实例的 ref 对象

例如

const Child = **React.forwardRef**(() => {

    const [count, setCount] = useState<number>(0);

    return (
        <>
            <button onClick={() => setCount(count + 1)}>+1</button>
            <button onClick={() => setCount(count - 1)}>-1</button>
        </>
    );
});

此时,在父组件内即可获取子组件的引用

// App.tsx 
import './App.css'

<Child **ref={componentRef}**></Child>

调用子组件内容

如果要在父组件通过 ref 访问子组件的实例,还需要使用 useImperativeHandle hook

ImperativeHandle 可以自定义暴露给外部组件哪些功能函数或属性

useImperativeHandle(通过forwardRef接收到的父组件的ref对象, () => 自定义ref对象, [依赖项数组]);

其中,第三个依赖数组项是可选的

import React, { useState, useImperativeHandle } from "react";

const Child = React.forwardRef((_, ref) => {

    const [count, setCount] = useState<number>(0);

    useImperativeHandle(ref, () => ({}));

    return (
        <>
            <button onClick={() => setCount(count + 1)}>+1</button>
            <button onClick={() => setCount(count - 1)}>-1</button>
        </>
    );
});

export default Child;

首先通过 forwardRef 接收父组件内接收子组件实例的 ref 对象,然后将这个 ref 传递给 imperativeHandle 内

第二个参数 () ⇒ ({}) 是子组件向父组件暴露的内容,可以通过这个对象声明要向父组件暴露哪些内容

例如,我希望将 count 和 setCount 暴露给 父组件,以实现在 父组件 内直接控制子组件 count 的数据

// Child.tsx
const Child = React.forwardRef((_, ref) => {

    const [count, setCount] = useState<number>(0);

    useImperativeHandle(ref, () => ({
        count,
        setCount
    }));

    return (
        <>
            <h1>Child Valus: {count}</h1>
            <button onClick={() => setCount(count + 1)}>+1</button>
            <button onClick={() => setCount(count - 1)}>-1</button>
        </>
    );
});