文章目录
- 一、什么是ref
- 二、在函数式组件中使用ref
-
- [1. useRef 获取dom](#1. useRef 获取dom)
- [2. forwardRef获取子组件的dom](#2. forwardRef获取子组件的dom)
- [3. useImperativeHandle将某些指定的行为暴露给父组件](#3. useImperativeHandle将某些指定的行为暴露给父组件)
- 三、在类组件中使用ref
-
- [1. createRef](#1. createRef)
- [2. 回调函数](#2. 回调函数)
- [3. 字符串](#3. 字符串)
一、什么是ref
在React中,ref是一个用于访问真实DOM节点或者React组件实例的对象。它允许您在组件中直接操作DOM元素或组件,而无需遵循传统的数据流。
使用ref,您可以:
-
访问和操作DOM:ref允许您通过将ref对象传递给组件中的元素来访问和修改真实的DOM。您可以使用ref来获取输入框的值、改变元素的样式、添加/删除/更新元素等等。
-
访问和调用组件方法:ref允许您访问在组件类上定义的方法。这对于在某些情况下需要从父组件中直接访问子组件的方法非常有用。
-
获取组件实例和进行事件监听:当使用类组件时,ref可以用来获取组件的实例,以便在需要时进行其他操作。您还可以使用ref来进行事件监听,例如在某个特定的事件发生时执行某些操作。
需要注意的是,在大多数情况下,最好遵循React的数据流原则,尽量避免直接操作DOM或访问子组件的方法
。只有当没有其他合适的选择并且确实需要这样做时,才应该使用ref。因为直接操作DOM或访问子组件的方法可能会破坏组件的封装性和可重用性。
二、在函数式组件中使用ref
1. useRef 获取dom
在React中,函数式组件使用ref属性可以获取到组件的实例或者某个Dom元素的引用。使用ref可以让你更方便地控制组件或Dom元素,并且可以在需要的时候访问和修改它们的属性和方法。
要在函数式组件中使用ref,你可以使用React提供的useRef
钩子函数。举一个例子,假设我们有一个函数式组件MyComponent
,其中包含了一个input元素:
javascript
import React, { useRef } from 'react';
const MyComponent = () => {
const inputRef = useRef(null);
const handleClick = () => {
// 使用 useRef 返回的 ref 对象来访问 input 的属性和方法
console.log(inputRef.current.value);
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={handleClick}>Focus Input</button>
</div>
);
};
export default MyComponent;
上述例子中,我们使用useRef
钩子函数来创建了一个名为inputRef
的引用。我们将这个引用传递给了input元素的ref属性,这样就可以通过inputRef.current
来获取该input的引用。
在函数式组件的handleClick函数中,我们可以通过inputRef.current
访问到input元素并获取到它的值。我们还可以使用inputRef.current.focus()
来让input元素获得焦点。
通过使用ref,我们可以方便地操纵组件或Dom元素,进行一些需要访问或修改属性和方法的操作。
注意,ref只能在函数式组件中使用,并且不能在函数式组件的子组件上使用
2. forwardRef获取子组件的dom
在React中,函数式组件的子组件上可以使用forwardRef
来使用ref
。forwardRef
函数可以将ref
传递给子组件,从而在子组件中使用ref
。
下面是一个示例,展示了如何在函数式组件的子组件中使用ref
:
js
import React, { forwardRef } from 'react';
// 子组件
const ChildComponent = forwardRef((props, ref) => {
return (
<input type="text" ref={ref} />
);
});
// 父组件
const ParentComponent = () => {
// 创建一个ref
const inputRef = React.createRef();
// 使用ref传递给子组件
return (
<div>
<ChildComponent ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>聚焦输入框</button>
</div>
);
};
export default ParentComponent;
在上面的例子中,ChildComponent
是一个函数式组件,通过将ref
作为forwardRef
的第二个参数,将其传递给内部的input
元素。然后,可以在ParentComponent
中创建一个ref
并将其传递给ChildComponent
。这样,我们就可以在父组件中操作子组件的input
元素,例如调用focus()
方法。
在按钮的onClick
事件处理函数中,我们可以通过inputRef.current
来获得子组件的input
元素,并调用它的focus()
方法将焦点聚焦到输入框上。
3. useImperativeHandle将某些指定的行为暴露给父组件
在React中,通过使用useImperativeHandle
钩子函数,函数式组件可以将某些指定的行为暴露给父组件。这在一些情况下非常有用,例如限制某些DOM行为,让父组件能够直接操作该组件的某些功能。
下面是一个例子,演示如何使用useImperativeHandle
来限制DOM行为:
js
import React, { useRef, useImperativeHandle, forwardRef } from 'react';
// 子组件
const ChildComponent = forwardRef((props, ref) => {
const childRef = useRef(null);
// 定义待暴露的函数
useImperativeHandle(ref, () => ({
// 在这里暴露特定的DOM行为
focus: () => {
childRef.current.focus();
},
// 在这里暴露特定的DOM行为
blur: () => {
childRef.current.blur();
}
}));
return <input ref={childRef} />;
});
// 父组件
const ParentComponent = () => {
const childRef = useRef(null);
const handleFocus = () => {
childRef.current.focus(); // 子组件的focus函数被父组件调用
};
const handleBlur = () => {
childRef.current.blur(); // 子组件的blur函数被父组件调用
};
return (
<div>
<ChildComponent ref={childRef} />
<button onClick={handleFocus}>Focus</button>
<button onClick={handleBlur}>Blur</button>
</div>
);
};
export default ParentComponent;
在上面的例子中,ChildComponent
是一个简单的函数式组件,它包含了一个<input>
元素。通过使用useImperativeHandle
钩子函数,并将ref
作为第一个参数传递进去,我们可以定义需要暴露给父组件的函数(在这里是focus
和blur
)。这意味着父组件可以通过ref
引用子组件,然后直接调用子组件的focus
和blur
函数。
在ParentComponent
中,通过使用useRef
来创建一个childRef
引用。然后,在handleFocus
和handleBlur
函数中,通过childRef.current
来访问ChildComponent
函数组件的focus
和blur
函数,从而直接操控子组件的DOM行为。
这样,我们就可以在父组件中通过按钮点击来控制子组件的DOM行为,实现了对DOM行为的限制。
三、在类组件中使用ref
1. createRef
在类式组件中,可以使用React.createRef()
来创建一个ref对象,然后将该ref对象附加到component的一个元素上,通过ref对象可以引用该元素并对其进行操作。
下面是一个使用ref的示例:
js
import React from "react";
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myDivRef = React.createRef(); // 创建一个ref对象
}
handleClick = () => {
this.myDivRef.current.style.backgroundColor = "blue"; // 使用ref对象引用元素并对其进行操作
}
render() {
return (
<div>
<div ref={this.myDivRef}>Hello, world!</div> {/* 将ref对象附加到元素上 */}
<button onClick={this.handleClick}>Change Color</button>
</div>
);
}
}
export default MyComponent;
在上面的示例中,我们首先在类的构造函数中创建一个ref对象myDivRef
。然后,通过将myDivRef
作为<div>
元素的ref
属性值,我们可以将ref对象附加到这个元素上。在handleClick
方法中,我们通过this.myDivRef.current
引用该元素并改变其背景颜色为蓝色。
这样,当点击按钮时,就会调用handleClick
方法,从而改变被ref引用的<div>
元素的背景颜色。
2. 回调函数
通过回调函数来设置ref
,在回调函数中将DOM元素分配给组件的实例属性。在组件的实例中,可以通过属性来访问该DOM元素。
js
import React, { Component } from 'react';
class ExampleComponent extends Component {
constructor(props) {
super(props);
this.myRef = null;
this.setRef = element => {
this.myRef = element;
};
}
componentDidMount() {
console.log(this.myRef); // 访问DOM元素
}
render() {
return <div ref={this.setRef}>Example</div>;
}
}
3. 字符串
使用字符串的ref
属性来获取DOM元素。这种方式在React v16.3
之前是支持的,但在较新的版本中已经过时,不建议使用。
js
import React, { Component } from 'react';
class ExampleComponent extends Component {
componentDidMount() {
console.log(this.refs.myRef); // 访问DOM元素
}
render() {
return <div ref="myRef">Example</div>;
}
}