一、useImperativeHandle()
useImperativeHandle(ref, createHandle, [deps])
useImperativeHandle
可以让你在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref
这样的命令式代码。useImperativeHandle
应当与forwardRef
一起使用。
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
在本例中,渲染 的父组件可以调用 inputRef.current.focus()。
二、forwardRef()
React.forwardRef
会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。
这种技术并不常见,但在以下两种场景中特别有用:
(1)转发refs
到 DOM 组件
(2)在高阶组件中转发refs
React.forwardRef
接受渲染函数作为参数。React 将使用 props
和 ref
作为参数来调用此函数。此函数应返回 React 节点。 FancyButton 使用 React.forwardRef
来获取传递给它的 ref
,然后转发到它渲染的 DOM button。这样,使用 FancyButton 的组件可以获取底层 DOM 节点 button 的 ref
,并在必要时访问,就像其直接使用 DOM button 一样。
const FancyButton = React.forwardRef((props, ref) => ( // Step:3
<button ref={ref} className="FancyButton"> // Step:4
{props.children}
</button>
));
const ref = React.createRef(); // Step:1
<FancyButton ref={ref}>Click me!</FancyButton>; // Step:2
在上述的示例中,React 会将
<FancyButton ref={ref}>
元素的ref
作为第二个参数传递给React.forwardRef
函数中的渲染函数。该渲染函数会将 ref 传递给<button ref={ref}>
元素。 因此,当React 附加了ref
属性之后,ref.current
将直接指向<button>
DOM 元素实例。 欲了解更多相关信息,请参阅官档refs
转发。
以下是对上述示例发生情况的逐步解释:(转发 refs
到 DOM 组件)
- 我们通过调用
React.createRef
创建了一个 React ref 并将其赋值给ref
变量。 - 我们通过指定 ref 为JSX 属性,将其向下传递给
<FancyButton ref={ref}>
。 - React 传递 ref 给
forwardRef
内函数(props, ref) => ...
,作为其第二个参数。 - 我们向下转发该 ref 参数到
<button ref={ref}>
,将其指定为 JSX 属性。 - 当 ref 挂载完成,
ref.current
将指向<button>
DOM 节点。
三、案例
父组件
1、注册
2、定义
3、触发
子组件
1、暴露子组件方法,将 forwardRef 接受的 ref 属性转发到其组件树下的另一个组件中
(1)
(2)
(3)父组件