React Ref
何时使用Refs
-
管理焦点,文本选择或者媒体播放
-
触发强制动画
-
继承第三放DOM库
避免使用refs来做任何可以通过声明式实现来完成的事件
创建Ref
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
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>
);
}
}
React 会在组件挂载时给 current
属性传入 DOM 元素,并在组件卸载时传入 null
值。ref
会在 componentDidMount
或 componentDidUpdate
生命周期钩子触发前更新。
class组件添加Ref
如果我们想包装上面的 CustomTextInput
,来模拟它挂载之后立即被点击的操作,我们可以使用 ref 来获取这个自定义的 input 组件并手动调用它的 focusTextInput
方法:
class AutoFocusTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
componentDidMount() {
this.textInput.current.focusTextInput();
}
render() {
return (
<CustomTextInput ref={this.textInput} />
);
}
}
请注意,这仅在 CustomTextInput
声明为 class 时才有效:
class CustomTextInput extends React.Component {
// ...
}
回调Refs
React也支持另一种i设置refs的方法,称为回调refs。它能助你更精准地控制何时refs被设置和解除
不同于传递createRef()
创建ref
属性,你会传递一个函数。这个函数中接收React组件实例或HTML DOM元素作为参数,以使它们能在其他地方被存储和访问
render() {
return (
<div>
<input
type="text"
ref={(element) => {this.textInput = element}}
/>
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
React将在组件挂载时,会调用ref
回调函数传入DOM元素,当卸载时会调用它并传入null
回调refs的扩展
如果ref
回调函数是以内联函数的方式定义的,即如以上代码所写,在更新过程(不包含初次渲染)中它会执行两次,第一次传入参数null
,然后第二次传入参数DOM元素。
这是因为每次渲染会创建一个新的实例,所以React清空旧的ref并且设置新得。通过将ref的回调定义成class绑定方式可以避免以上问题
saveInput = (c) => {
this.input1 = c
}
render() {
return (
<div>
<input
type="text"
ref={this.saveInput}
/>
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}