React Hooks之useRef、createRef、forwardRef

一 Ref(reference)引用:用于直接使用dom元素的某个方法,或者直接使用自定义组件中的某个方法。处理对象:管理焦点,文本选择,媒体播放(媒体回放);触发动画;集成第三方的DOM库。

  1. 作用于内置的html组件,得到的是真实的dom
  2. ref作用于类组件,得到的是类的实例
  3. ref不能作用于函数组件
  4. Ref不推荐字符串方式,一般是函数或者对象方式引用。
import React, { Component, createRef } from 'react';

export default class Test extends Component {
  constructor(props){
    super(props)
    this.createRefTxt = createRef()
  }
  handleFnClick = () => {
    console.log(this.fnTxt);
    this.fnTxt.focus();
  };

  handleObjectClick = () => {
    console.log(this.createRefTxt);
    this.createRefTxt.current.focus();
  };

  render () {
    return (
      <>
        <div className="func-way">
          <input
            ref={(el) => { this.fnTxt = el; }}
            type='text'
          />
          <button onClick={this.handleFnClick}>函数方式</button>
        </div>
        <div className="object-way">
          <input
            ref={this.createRefTxt}
            type='text'
          />
          <button onClick={this.handleObjectClick}>对象方式</button>
        </div>
      </>

    );
  }
}
View Code

 

二 useRef、createRef、forwardRef区别:

1 useRef:

一般用于函数组件

useRef 不仅仅是用来管理 DOM ref 的,它还相当于 this , 可以存放任何变量。

当 useRef 的内容发生变化时,它不会通知您。更改.current属性不会导致组件重新渲染。因为他一直是一个引用 。

 

2 createRef:

一般用于类组件,React.createRef 创建一个能够通过 ref 属性附加到 React 元素的 ref。

如果用于函数组件中,当App这个函数组件被重新渲染时,App函数将会执行,并且重新创建、初始化所有的变量和表达式。因此,createRef每次都会被执行,所以对应的值总是为null。

createRef 每次渲染都会返回一个新的引用,而 useRef 每次都会返回相同的引用。

 

3 forwardRef:

Ref 转发是一个可选特性,其允许某些组件接收 ref,并将其向下传递(换句话说,“转发”它)给子组件。

import React, { Component } from 'react'

function A(props, ref){
  console.log(props, ref)
  return <h1 ref={ref}>A组件</h1>
}

// 传递函数组件,得到一个新的组件,不能传递类组件,并且函数组件必须使用第二个
const NewA = React.forwardRef(A)
export default class Test extends Component {
  ARef = React.createRef()
  
  componentDidMount() {
    console.log(this.ARef) // {current: h1}
  }
  
  render() {
    return (
      <div>
        <NewA ref={this.ARef} words="sdfsd"/>
      </div>
    )
  }
}
View Code

 

4 父组件调用子组件方法:

import React, { Component, createRef } from 'react';

class CustomTextInput extends Component {
  constructor(props) {
    super(props);
    this.focus = this.focus.bind(this);
  }
  focus () {
    // Explicitly focus the text input using the raw DOM API
    this.textInput.focus();
  }

  handleChild = () => {
    console.log('父组件调用子组件方法')
  }

  render () {
    // Use the `ref` callback to store a reference to the text input DOM
    // element in an instance field (for example, this.textInput).
    return (
      <div>
        <input
          type="text"
          ref={(input) => { this.textInput = input; }} />
        {/* //此时input参数就是表示该DOM本身 */}
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focus}
        />
      </div>
    );
  }
}

export default class Test extends Component {
  componentDidMount () {
    console.log(this.textInput);
    //父组件自动调用子组件CustomTextInput实例的focus方法
    this.textInput.focus();
  }

  handleClick = () => {
    this.textInput.handleChild();
  }

  render () {
    return (
      <div>
        <CustomTextInput
          ref={(input) => { this.textInput = input; }} />
        <button onClick={this.handleClick}>父组件按钮</button>
      </div>

    );
  }
}
View Code

 

三 useRef与createRef更新:useRef与createRef更新区别

能够获取上一次值的原因:由于 useEffect 在 Render 完毕后才执行,因此 ref 的值在当前 Render 中永远是上一次 Render 时候的,我们可以利用它拿到上一次 Props

import React, { useState, createRef, useRef, useEffect } from 'react';

const Child1 = () => {
  const [count, setCount] = useState(0);
  const preCountUserRef = useRef();
  console.log(count);
  useEffect(() => {
    preCountUserRef.current = count;
  });
  return (
    <div>
      <p>preCount:{preCountUserRef.current}</p>
      <p>You clicked {count} times</p>
      <button onClick={() => { setCount(count + 1) }}>Click me</button>
    </div>
  )
}

export default Child1
View Code

 

 

 

 

posted @ 2021-08-12 11:33  TerryMin  阅读(707)  评论(0编辑  收藏  举报