、 等。当一个Ref被附加到一个这些原生HTML元素上时,它会接收到该元素的实际DOM节点作为其current属性的值。例如,直接将Ref附加到原生input元素:
import React, { useRef, useEffect } from 'react';
function MyInput() {
const inputRef = useRef(null);
useEffect(() => {
if (inputRef.current) {
inputRef.current.focus(); // 直接访问DOM节点并调用其方法
}
}, []);
return <input type="text" ref={inputRef} />;
} Ref转发(Ref Forwarding)
在构建可复用组件时,我们经常需要将一个Ref从父组件传递(转发)给子组件,特别是当子组件需要访问其内部的DOM节点或另一个组件实例时。React提供了React.forwardRef高阶组件来处理这种情况。
1. Ref转发到功能组件
功能组件默认不能直接接收Ref,因为它们没有实例。但通过React.forwardRef,我们可以让功能组件接收Ref并将其转发给内部的DOM元素或另一个组件。
Delphi 7应用编程150例 全书内容 CHM版
Delphi 7应用编程150例 CHM全书内容下载,全书主要通过150个实例,全面、深入地介绍了用Delphi 7开发应用程序的常用方法和技巧,主要讲解了用Delphi 7进行界面效果处理、图像处理、图形与多媒体开发、系统功能控制、文件处理、网络与数据库开发,以及组件应用等内容。这些实例简单实用、典型性强、功能突出,很多实例使用的技术稍加扩展可以解决同类问题。使用本书最好的方法是通过学习掌握实例中的技术或技巧,然后使用这些技术尝试实现更复杂的功能并应用到更多方面。本书主要针对具有一定Delphi基础知识
下载
import React, { useRef, useEffect } from 'react';
// FancyButton 是一个功能组件,通过 forwardRef 接收并转发 Ref
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
function App() {
const buttonRef = useRef(null);
useEffect(() => {
if (buttonRef.current) {
console.log('Button DOM element:', buttonRef.current);
buttonRef.current.style.backgroundColor = 'lightblue';
}
}, []);
return (
<FancyButton ref={buttonRef}>
点击我
</FancyButton>
);
} 在这个例子中,FancyButton内部渲染了一个原生的元素。通过React.forwardRef,App组件传递的buttonRef最终会指向这个原生的DOM节点。
2. Ref转发到类组件实例
React文档中提到:“Ref转发不限于DOM组件。你也可以将Refs转发给类组件实例。”这句的关键在于“类组件实例”。当Ref被转发给一个类组件时,ref.current将指向该类组件的实例本身,而不是其内部渲染的DOM节点(除非类组件内部再次将Ref转发给其子DOM)。这意味着你可以访问该类组件实例的所有公共方法和属性。
考虑以下场景,一个父组件需要访问子类组件的某个方法或内部状态:
import React, { useRef, useEffect } from 'react';
// 子类组件
class MyClassComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: props.initialValue || ''
};
this.inputRef = React.createRef(); // 内部Ref用于访问自己的DOM元素
}
// 类组件的公共方法
focusInput = () => {
if (this.inputRef.current) {
this.inputRef.current.focus();
}
};
render() {
// 这里的 innerRef 是通过 props 接收的外部 Ref
// 它将指向 MyClassComponent 的实例
return (
<div>
<label>{this.props.label}: </label>
<input
type="text"
value={this.state.value}
onChange={(e) => this.setState({ value: e.target.value })}
ref={this.inputRef} // 内部 Ref 绑定到 input 元素
/>
{/* 如果需要将外部 Ref 绑定到这个 input,则需要将 innerRef 传递给它,
但这里我们展示的是外部 Ref 绑定到类组件实例本身的情况 */}
</div>
);
}
}
// 使用 React.forwardRef 将 Ref 转发给 MyClassComponent
const ForwardedMyClassComponent = React.forwardRef((props, ref) => {
// 注意:这里的 ref 是外部传进来的,它将指向 MyClassComponent 的实例
// 我们将它作为 props 传递给 MyClassComponent
return <MyClassComponent {...props} instanceRef={ref} />;
});
// 父组件
function ParentComponent() {
const classComponentRef = useRef(null); // 这个 Ref 将指向 MyClassComponent 的实例
useEffect(() => {
if (classComponentRef.current) {
console.log('Class component instance:', classComponentRef.current);
// 可以调用类组件实例的方法
classComponentRef.current.focusInput();
}
}, []);
return (
<ForwardedMyClassComponent
label="用户名"
initialValue="ReactUser"
ref={classComponentRef} // 将 Ref 传递给 ForwardedMyClassComponent
/>
);
}
export default ParentComponent; 在这个示例中,ParentComponent通过classComponentRef获取到MyClassComponent的实例。然后,它可以通过classComponentRef.current直接调用MyClassComponent实例上的focusInput方法。
关键点在于:
当Ref直接绑定到原生HTML元素(“DOM组件”)时,ref.current是该DOM节点。
当Ref通过React.forwardRef转发给一个功能组件 ,且功能组件将Ref绑定到其内部的原生HTML元素 时,ref.current也是该DOM节点。
当Ref通过React.forwardRef转发给一个类组件 时,ref.current是该类组件的实例 。这意味着你可以访问该类组件实例的所有公共方法和属性。
总结与注意事项
Refs的使用场景: Refs主要用于处理那些不能通过声明式方法(props和state)完成的任务,例如管理焦点、触发动画、集成第三方DOM库等。
避免过度使用Refs: 大多数组件交互和数据流应该通过props和state来管理。Refs应该作为“逃生舱口”,仅在必要时使用。
Ref转发的必要性: 当你需要父组件访问子组件内部的DOM节点或子组件实例时,Ref转发是必不可少的。
区分Ref指向: 清楚理解Ref在不同场景下(原生DOM元素、功能组件内部DOM、类组件实例)所指向的具体内容。
类组件中的Ref访问: 在类组件内部,你可以通过this.props.innerRef(如果Ref作为innerRef传递)或通过React.createRef()创建的内部Ref来访问DOM元素或子组件。
通过深入理解Refs与DOM组件和类组件的交互方式,开发者可以更有效地利用React的强大功能,构建出高性能、可维护的复杂应用。