Ref获取DOM★★★

165 阅读4分钟

createRef 主要用于 class 组件。而函数组件通常使用 useRef

类组件获取方式 ★★★

createRef 创建一个 ref 对象,该对象可以包含任意值。 createRef 返回一个对象,该对象只有一个属性:

  • current:初始值为 null,你可以稍后设置为其他内容。如果你把 ref 对象作为 JSX 节点的 ref 属性传递给 React,React 将设置其 current 属性。

注意事项 

  • createRef 总是返回一个 不同的 对象。这相当于你自己编写了 { current: null }
  • 在函数组件中,你可能想要使用 useRef,因为它始终返回相同的对象。
  • const ref = useRef() 等同于 const [ref, _] = useState(() => createRef(null))
import React, { PureComponent, createRef } from 'react'

export class App extends PureComponent {
  constructor() {
    super()
    this.state = {

    }
    this.h1 = createRef()
    this.element3 = null
  }
  getDOM() {
    // 在React元素上绑定一个ref字符单
    // console.log(this.refs.h2);
    //·2提前创建好ref对象,createRef(),将创建出来的对象绑定到元素
    // console.log(this.h1.current);
   // 传入一个回调函数,在对应的元素被渲染之后,回调函数被执行,并且将元素传入
    console.log(this.element3);
  }
  render() {
    return (
      <div>
        <h2 ref="h2">第一种</h2>
        <h1 ref={this.h1}>第二种</h1>
        <h3 ref={el => { this.element3 = el }}>测试第三种</h3>
        <button onClick={e => this.getDOM()}>获取原生DOM</button>
      </div>
    )
  }
}

export default App

函数式获取方式★★★

useRef★★★

useRef 是一个 React Hook,它能帮助引用一个不需要渲染的值。

const ref = useRef(initialValue)

参数 

  • initialValue:ref 对象的 current 属性的初始值。可以是任意类型的值。这个参数在首次渲染后被忽略。

返回值 

useRef 返回一个只有一个属性的对象:

  • current:初始值为传递的 initialValue。之后可以将其设置为其他值。如果将 ref 对象作为一个 JSX 节点的 ref 属性传递给 React,React 将为它设置 current 属性。

在后续的渲染中,useRef 将返回同一个对象。

注意 

  • 可以修改 ref.current 属性。与 state 不同,它是可变的。然而,如果它持有一个用于渲染的对象(例如 state 的一部分),那么就不应该修改这个对象。
  • 改变 ref.current 属性时,React 不会重新渲染组件。React 不知道它何时会发生改变,因为 ref 是一个普通的 JavaScript 对象。
  • 除了 初始化 外不要在渲染期间写入或者读取 ref.current,否则会使组件行为变得不可预测。
  • 在严格模式下,React 将会 调用两次组件方法,这是为了 帮助发现意外问题。但这只是开发模式下的行为,不会影响生产模式。每个 ref 对象都将会创建两次,但是其中一个版本将被丢弃。如果使用的是组件纯函数(也应当如此),那么这不会影响其行为。
import React, { useRef } from 'react'

export function App() {
  const h1 = useRef(null)
  function getDOM() {
    console.log(h1.current);
  }
  return (
    <div>
      <h1 ref={h1}>第二种</h1>
      <button onClick={e => getDOM()}>获取原生DOM</button>
    </div>
  )
}

export default App

获取子组件实例方式

import React, { PureComponent, createRef } from 'react'

class Son extends PureComponent {
  test() {
    console.log("我被父组件获取调用了");
  }
  render() {
    return (
      <h1>我是子组件</h1>
    )
  }
}

export default class App extends PureComponent {
  constructor() {
    super()
    this.SonRef = createRef()
  }
  getEL() {
    this.SonRef.current.test()
  }
  render() {
    return (
      <div>
        <Son ref={this.SonRef}></Son>
        <button onClick={e => this.getEL()}>获取子组件实例</button>
      </div>
    )
  }
}

在此实例中我们获取子组件方式也是使用createRef来获取实例,然后进行.test()来调用子组件的方法。

有点像vue中的调用子组件方法一样,也是先通过ref获取子组件实例然后调用子组件的数据或方法;

但是对于函数式组件若要获取子组件实例则需要另一种方式去完成此操作!

forwardRef ★★★

forwardRef 允许组件使用 ref 将 DOM 节点暴露给父组件。

const SomeComponent = forwardRef(render)

参数 

  • render:组件的渲染函数。React 会调用该函数并传入父组件传递的 props 和 ref。返回的 JSX 将作为组件的输出。

返回值

forwardRef 返回一个可以在 JSX 中渲染的 React 组件。与作为纯函数定义的 React 组件不同,forwardRef 返回的组件还能够接收 ref 属性。

render 函数

forwardRef 接受一个渲染函数作为参数。React 将会使用 propsref 调用此函数:

参数 

  • props:父组件传递过来的 props。
  • ref:父组件传递的 ref 属性。ref 可以是一个对象或函数。如果父组件没有传递一个 ref,那么它将会是 null。你应该将接收到的 ref 转发给另一个组件,或者将其传递给 useImperativeHandle

返回值 

forwardRef 返回一个可以在 JSX 中渲染的 React 组件。与作为纯函数定义的 React 组件不同,forwardRef 返回的组件还能够接收 ref 属性。

import React, { PureComponent, createRef, forwardRef } from 'react'

const Son=forwardRef(function (props, ref) {
  return (
    <h1 ref={ref}>我是子组件</h1>
  )
})

export default class App extends PureComponent {
  constructor() {
    super()
    this.SonRef = createRef()
  }
  getEL() {
    console.log(this.SonRef.current);
  }
  render() {
    return (
      <div>
        <Son ref={this.SonRef}></Son>
        <button onClick={e => this.getEL()}>获取子组件实例</button>
      </div>
    )
  }
}