Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。
创建 Refs
Refs 是使用 React.createRef()
创建的,并通过 ref
属性附加到 React 元素。在构造组件时,通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们。
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef(); }
render() {
return <div ref={this.myRef} />; }
}
访问 Refs
当 ref 被传递给 render
中的元素时,对该节点的引用可以在 ref 的 current
属性中被访问。
const node = this.myRef.current;
ref 的值根据节点的类型而有所不同:
- 当
ref
属性用于 HTML 元素时,构造函数中使用React.createRef()
创建的ref
接收底层 DOM 元素作为其current
属性。 - 当
ref
属性用于自定义 class 组件时,ref
对象接收组件的挂载实例作为其current
属性。 - 你不能在函数组件上使用
ref
属性,因为他们没有实例。
例子
为 DOM 元素添加 ref
以下代码使用 ref
去存储 DOM 节点的引用:
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// 创建一个 ref 来存储 textInput 的 DOM 元素
this.textInput = React.createRef();
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// 直接使用原生 API 使 text 输入框获得焦点
// 注意:我们通过 "current" 来访问 DOM 节点
this.textInput.current.focus();
}
render() {
// 告诉 React 我们想把 <input> ref 关联到
// 构造器里创建的 `textInput` 上
return (
<div>
<input
type="text"
ref={this.textInput} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
ReactDOM.render(
<CustomTextInput />,
document.getElementById('root')
);
React 会在组件挂载时给 current
属性传入 DOM 元素,并在组件卸载时传入 null
值。ref
会在 componentDidMount
或 componentDidUpdate
生命周期钩子触发前更新。
为class组件添加ref
如果想包装上面的 CustomTextInput
,来模拟它挂载之后立即被点击的操作,我们可以使用 ref 来获取这个自定义的 input 组件并手动调用它的 focusTextInput
方法:
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// 创建一个 ref 来存储 textInput 的 DOM 元素
this.textInput = React.createRef();
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// 直接使用原生 API 使 text 输入框获得焦点
// 注意:我们通过 "current" 来访问 DOM 节点
this.textInput.current.focus();
}
render() {
// 告诉 React 我们想把 <input> ref 关联到
// 构造器里创建的 `textInput` 上
return (
<div>
<input
type="text"
ref={this.textInput} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
class AutoFocusTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
componentDidMount() {
this.textInput.current.focusTextInput();
}
render() {
return (
<CustomTextInput ref={this.textInput} />
);
}
}
ReactDOM.render(
<AutoFocusTextInput />,
document.getElementById('root')
);
Refs 与函数组件
默认情况下,你不能在函数组件上使用 ref
属性,因为它们没有实例:
function MyFunctionComponent() {
return <input />
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
render() {
// this will not work!
return (
<MyFunctionComponent ref={this.textInput} />
)
}
}
如果要在函数组件中使用 ref
,你可以使用 forwardRef
(可与 useImperativeHandle
结合使用),或者可以将该组件转化为 class 组件。
不管怎样,你可以在函数组件内部使用 ref
属性,只要它指向一个 DOM 元素或 class 组件:
function CustomTextInput(props) {
// 这里必须声明 textInput,这样 ref 才可以引用它
const textInput = useRef(null);
function handleClick() {
textInput.current.focus();
}
return (
<div>
<input
type="text"
ref={textInput} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
);
}