3. 获取DOM方式refs
3.1. 如何使用Ref
-
- 在React的开发模式中,通常情况下不需要、也不建议直接操作原生DOM,但是某些特殊的情况,确实需要获取到DOM进行某些操作;
- 1.1. 管理焦点,文本选择或媒体播放;
- 1.2. 触发强制动画;
- 1.3. 集成第三方DOM库;
- 1.4. 我们可以通过refs获取DOM;
-
- 如何创建refs来获取对应的DOM呢?目前有三种方式:
-
2.1. 方式一: 在React元素上绑定一个ref字符串(这种方式获取ref元素会被废弃,
不推荐使用) -
2.2. 方式二:
提前创建好ref对象,createRef(), 将创建出来的对戏那个绑定到元素上(推荐使用这种方式) -
2.3. 方式三:
传入一个回调函数,在对应的元素被渲染之后,回调函数被执行,并且将元素传入 -
2.4. 示例代码如下:
jsimport React, { PureComponent, createRef } from 'react' export class App extends PureComponent { constructor() { super() this.state = { } // 1. 创建的ref不涉及页面更新的东西,不涉及到渲染的东西 this.titleRef = createRef() this.titleEl = null } getNativeDom () { // 不建议这样拿原生dom // const h2El = document.querySelector('h2') // 1. 方式一: 在React元素上绑定一个ref字符串(这种方式获取ref元素会被废弃,不推荐使用) // console.log(this.refs.why) // 2. 方式二: 提前创建好ref对象,createRef(), 将创建出来的对戏那个绑定到元素上(推荐使用这种方式) // console.log(this.titleRef.current) // 3. 方式三: 传入一个回调函数,在对应的元素被渲染之后,回调函数被执行,并且将元素传入 console.log(this.titleEl) } render() { return ( <div> <h2 ref='why'>Hello World</h2> <div ref={this.titleRef}>你好啊,李银河</div> {/* 传入一个函数,当元素渲染出来之后自动回调这个函数,回调函数时并把元素作为参数传递给这个函数 */} <div ref={el => this.titleEl = el }>你好啊,世界</div> <button onClick={(e) => this.getNativeDom()}>获取ref元素</button> </div> ) } } export default App
3.2. ref获取类组件实例
-
- 类组件的ref获取方式和绑定元素类似,通过ref属性绑定组件实例
-
- 示例代码如下:
jsximport React, { PureComponent, createRef } from 'react' export class HelloWorld extends PureComponent { test () { console.log('------') } render() { return ( <div> <h2>Hello World!</h2> </div> ) } } export class App extends PureComponent { constructor() { super() this.state = { } // 1. 创建的ref不涉及页面更新的东西,不涉及到渲染的东西 this.hwRef = createRef() } getComponent () { console.log(this.hwRef.current) this.hwRef.current.test() } render() { return ( <div> <HelloWorld ref={this.hwRef} /> <button onClick={(e) => this.getComponent()}>获取组件实例</button> </div> ) } } export default App
3.3. ref获取函数组件(ref的转发)
-
- 在前面我们学习ref时讲过,ref不能应用于函数式组件;
- 1.1. 因为函数式组件没有实例,所以不能获取对应的组件对象
-
- 但是,在开发中我们可能想要获取函数式组件中某个元素的DOM,这个时候我们应该如何操作呢?
- 方式一: 直接传入ref属性(错误的做法)
- 方式二: 通过forwardRef()高阶函数
-
- 示例代码如下:
jsximport React, { PureComponent, createRef, forwardRef } from 'react' const HelloWorld = forwardRef (function (props, ref) { // 1. 在前面学习的ref,ref不能应用于函数式组件 // - 1.1. 函数式组件没有实例,所以不能获取对应的组件对象; // 2. 通过forwardRef高阶函数; return ( <div> <h2 ref={ref}>Hello World!</h2> <p>哈哈哈</p> </div> ) }) export class App extends PureComponent { constructor() { super() this.state = { } // 1. 创建的ref不涉及页面更新的东西,不涉及到渲染的东西 this.hwRef = createRef() } getComponent () { console.log(this.hwRef.current) } render() { return ( <div> <HelloWorld ref={this.hwRef} /> <button onClick={(e) => this.getComponent()}>获取函数组件实例</button> </div> ) } } export default App
3.4. ref的类型
-
- ref的值根据节点的类型而有所不同
- 1.1. 当ref属性用于HTML元素时,构造函数中使用React.createRef()创建的ref接受底层DOM元素作为其current属性
- 1.2. 当ref属性用于自定义class组件时,ref对象接收组件的实例作为其current属性
- 1.3. 不能在函数组件上使用ref属性,因为他们没有实例
-
- 函数组件是没有实例的,所以无法通过ref获取他们的实例:
- 2.1. 但是某些时候,我们可能想要获取函数式组件中的某个DOM元素;
- 2.2. 这个时候我们可以通过React.forwardRef(), 当ref属性用于通过forwardRef转发的函数式组件时,ref对象接收组件内部转发的具体元素或组件实例作为其current属性。
- 2.3. 后面还会记录到hooks中如何使用ref;