ref 的作用是获取实例,但由于函数组件不存在实例,因此无法通过 ref 获取函数组件的实例引用
<Child ref={componentRef}></Child>
// 不能将类型“{ ref: MutableRefObject<undefined>; }”分配给类型“IntrinsicAttributes”。
// 类型“IntrinsicAttributes”上不存在属性“ref”。ts(2322)
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>
</>
);
});