-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Refs
Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。
何时使用 Refs
- 管理焦点,文本选择或媒体播放
- 出发强制动画
- 集成第三方库
注意:避免使用 refs 来做任何可以通过声明式实现来完成的事情,请勿过度使用 refs
使用 Refs 的方式
目前为止,共有三种使用 refs 的方式方法,下面按照新旧顺序来写
- React.createRef() // React 16.3 版本及以上
- 回调 refs // React 16.3 版本以下
- String 类型的 Refs // 已过时,未来可能会被移除
一、React.createRef()
创建 Refs
Refs 是使用 React.createRef() 创建的,并通过 ref 属性附加到 React 元素。在构造组件时,通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们。
访问 Refs
当 React.createRef() 创建的 ref 被传递给 render 中的元素时,对该节点的引用可以在 ref 的 current 属性中被访问。
const node = this.myRef.current
ref 的值根据节点的类型而有所不同:
- 当
ref属性用于 HTML 元素时,构造函数中使用React.createRef()创建的ref接收底层 DOM 元素作为其current属性。 - 当
ref属性用于自定义 class 组件时,ref对象接收组件的挂载实例作为其current属性。 - 当
ref属性用于自定义 class 组件时,ref对象接收组件的挂载实例作为其current属性。
React 会在组件挂载时给 current 属性传入 DOM 元素,并在组件卸载时传入 null 值。ref 会在 componentDidMount 或 componentDidUpdate 生命周期钩子触发前更新。
将 DOM Refs 暴露给父组件
在极少数情况下,你可能希望在父组件中引用子节点的 DOM 节点。通常不建议这样做,因为它会打破组件的封装,但它偶尔可用于触发焦点或测量子 DOM 节点的大小或位置。
虽然你可以向子组件添加 ref,但这不是一个理想的解决方案,因为你只能获取组件实例而不是 DOM 节点。并且,它还在函数组件上无效。
如果你使用 16.3 或更高版本的 React, 这种情况下我们推荐使用 ref 转发。Ref 转发使组件可以像暴露自己的 ref 一样暴露子组件的 ref。关于怎样对父组件暴露子组件的 DOM 节点,在 ref 转发文档中有一个详细的例子。
如果你使用 16.2 或更低版本的 React,或者你需要比 ref 转发更高的灵活性,你可以使用这个替代方案将 ref 作为特殊名字的 prop 直接传递。
可能的话,我们不建议暴露 DOM 节点,但有时候它会成为救命稻草。注意这个方案需要你在子组件中增加一些代码。如果你对子组件的实现没有控制权的话,你剩下的选择是使用 findDOMNode(),但在严格模式 下已被废弃且不推荐使用。
二、回调 Refs
回调 Refs 可以让我们更精细的控制何时 refs 被设置和解除
<input type="text" ref={e => this.myRef = e}/>
React 将在组件挂载时,会调用 ref 回调函数并传入 DOM 元素,当卸载时调用它并传入 null。在 componentDidMount 或 componentDidUpdate 触发前,React 会保证 refs 一定是最新的。
可以在组件间传递回调形式的 refs,就像你可以传递通过 React.createRef() 创建的对象 refs 一样。
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
class Parent extends React.Component {
render() {
return (
<CustomTextInput
inputRef={el => this.inputElement = el}
/>
);
}
}
在上面的例子中,Parent 把它的 refs 回调函数当作 inputRef props 传递给了 CustomTextInput,而且 CustomTextInput 把相同的函数作为特殊的 ref 属性传递给了 ``。结果是,在 Parent 中的 `this.inputElement` 会被设置为与 `CustomTextInput` 中的 `input` 元素相对应的 DOM 节点。
注意:组件间传递 refs 时,传递 refs 的 props 属性名 不能是 ref
关于回调 refs 的说明
如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。
三、 过时 API:String 类型的 Refs
这是最原始的使用 refs 的方式,可以通过 this.refs.textInput 来访问 DOM 节点。现在官方已经 不建议使用它,因为 string 类型的 refs 存在 一些问题。它已过时并可能会在未来的版本被移除。
问题
- 它要求 React 跟踪当前的渲染组件(因为它无法猜测 this),使得 React 变慢
- 它不能像大多数人期望的那样使用“渲染回调”模式
- 它是不可组合的,即,如果一个库在传递的子库上放了一个引用 ref,则用户无法在其上放置另一个引用 ref。回调引用完全可以组合。