对于ref转发,官网中有这样的描述
Ref转发是一项将 ref 自动地通过组件传递到其子组件的技巧。对于大多数应用中的组件来说,这通常不是必需的。但其对某些组件,尤其是可重用的组件库是很有用的。
让我们简单的翻译一下:React.forwardRef 是 React 中的一个高级 API,它用于在组件之间传递 ref。通常情况下,当你创建一个组件时,ref 是无法传递给组件的子元素的,但是使用 React.forwardRef 可以解决这个问题。
React.forwardRef(render)的返回值是react组件,接收的参数是一个render函数,函数签名为render(props, ref),第二个参数将其接受的 ref 属性转发到render返回的组件中。
这项技术在以下两种场景中特别有用:
- 封装第三方组件:如果你在自己的组件中使用了第三方的组件,并且希望通过
ref控制第三方组件,可以使用React.forwardRef; - 高阶组件(HOC):在创建高阶组件的时候,
React.forwardRef可以用来保留原始组件的ref
场景一:封装第三方的组件
假设你使用了一个第三方的输入框组件,但是你想在父组件中控制这个输入框的焦点,使用React.forwardRef 可以帮助你将ref传递给第三方组件。
import React, { forwardRef, useEffect, useRef } from 'react';
import ThirdPartyInput from 'third-party-input';
const CustomInput = forwardRef((props, ref) => {
const inputRef = useRef(null);
useEffect(() => {
// 这里可以添加一些额外的逻辑
// 例如:聚焦输入框
if (ref) {
ref.current = {
focus: () => {
if (inputRef.current) {
inputRef.current.focus();
}
}
};
}
}, [ref]);
return <ThirdPartyInput ref={inputRef} {...props} />;
});
// 在父组件中使用 CustomInput
const ParentComponent = () => {
const customInputRef = useRef(null);
const handleButtonClick = () => {
// 在按钮点击时聚焦输入框
if (customInputRef.current) {
customInputRef.current.focus();
}
};
return (
<div>
<CustomInput ref={customInputRef} />
<button onClick={handleButtonClick}>Focus Input</button></div>
);
};
场景二:高阶组件(HOC)
在高阶组件的场景中,你可以使用 React.forwardRef来确保传递给高阶组件的 ref能够正确地传递给原始组件。
import React, { forwardRef } from 'react';
// 高阶组件
const withLogging = (WrappedComponent) => {
const WithLogging = forwardRef((props, ref) => {
// 在这里添加一些日志记录的逻辑
console.log('Component is rendered with props:', props);
// 将 ref 传递给原始组件
return <WrappedComponent {...props} ref={ref} />;
});
return WithLogging;
};
// 创建原始组件
const MyComponent = ({ label }, ref) => {
return (
<div ref={ref}>
<p>{label}</p>
</div>
);
};
// 使用高阶组件
const MyComponentWithLogging = withLogging(MyComponent);
// 在父组件中使用 MyComponentWithLogging
const ParentComponent = () => {
const myComponentRef = React.createRef();
return (
<div>
<MyComponentWithLogging label="Hello" ref={myComponentRef} />
{/* 在这里可以通过 myComponentRef 控制 MyComponentWithLogging 组件 */}
</div>
);
};