react学习—ref

ref

  • 一、ref
    • 1、ref基础
    • 2、ref标记一个组件
    • 3、ref使用对象
    • 4、ref使用函数
      • 1.行间函数
      • 2.声明调用

一、ref

1、ref基础

如果我们需要通过一些操作获取某些dom元素怎么办呢?
如点击按钮使得输入框对焦,用js的document当然可以,但是react中提供了更好地方法ref
在这里插入图片描述

import React, {
      Component } from 'react'

export default class Comp extends Component {
     
  handleClick = () => {
     
  	console.log(this);
    this.refs.txt.focus();
    console.log('input获取焦点');
  }
  render() {
     
    return (
      <div>
        <input ref="txt" type="text" name="" id=""/>
        <button onClick={
     this.handleClick}>按钮</button>
      </div>
    )
  }
}

使用ref设置一个类似id的标记,就可以通过这个标记找到该dom元素。
react学习—ref_第1张图片
我们查看输出的this就知道,ref中就有了我们设置的txt标记。
react学习—ref_第2张图片
注意:ref并不是一个属性哦
react学习—ref_第3张图片
ref作用于内置的html组件,得到的将是真实的dom对象

2、ref标记一个组件

再创建一个类组件A,并在Comp中使用A并标记。

import React, {
      Component } from 'react'

class A extends Component {
     
  method() {
     
    console.log("这是类组件A的method方法");
  }
  render() {
     
    return <h1>类组件A</h1>
  }
}

export default class Comp extends Component {
     
  handleClick = () => {
     
    console.log(this);
    this.refs.txt.focus();
    console.log('input获取焦点');
  }
  render() {
     
    return (
      <div>
        <input ref="txt" type="text" name="" id=""/>
        <button onClick={
     this.handleClick}>按钮</button>
        <A ref="compA" />
      </div>
    )
  }
}

我们发现,Comp中this就已经能够得到组件A的信息了。
react学习—ref_第4张图片
甚至通过ref标记,我们能使用类组件A中的方法,

export default class Comp extends Component {
     
  handleClick = () => {
     
    console.log(this);
    this.refs.txt.focus();
    console.log('input获取焦点');
    this.refs.compA.method();
  }
  render() {
     
    return (
      <div>
        <input ref="txt" type="text" name="" id=""/>
        <button onClick={
     this.handleClick}>按钮</button>
        <A ref="compA" />
      </div>
    )
  }
}

react学习—ref_第5张图片
ref作用于类组件,得到的将是类的实例
为甚这里说是类组件呢?我们来试试函数组件。

import React, {
      Component } from 'react'

class A extends Component {
     
  method() {
     
    console.log("这是类组件A的method方法");
  }
  render() {
     
    return <h1>类组件A</h1>
  }
}
function B(){
     
  return <h1>函数组件B</h1>
}

export default class Comp extends Component {
     
  handleClick = () => {
     
    console.log(this);
    this.refs.txt.focus();
    console.log('input获取焦点');
    this.refs.compA.method();
  }
  render() {
     
    return (
      <div>
        <input ref="txt" type="text" name="" id=""/>
        <button onClick={
     this.handleClick}>按钮</button>
        <A ref="compA" />
        <B ref="compB" />
      </div>
    )
  }
}

函数组件只是返回一个react元素dom,所以react认为给函数组件ref没有什么意义。但是函数组件内部可以使用ref。

function B(){
     
  return <h1 ref="b">函数组件B</h1>
}

ref不能作用于函数组件
react学习—ref_第6张图片
到此为止,是不是觉得ref很好用呢?但是:
ref不再推荐使用字符串赋值,字符串赋值的方式将来可能会被移出

目前,ref推荐使用对象或者是函数

3、ref使用对象

使用React.createRef()

import React, {
      Component } from 'react'


export default class Comp extends Component {
     
  constructor(props) {
     
    super(props);
    this.txt = React.createRef();
    console.log(this.txt);
  }
  render() {
     
    return (
      <div>
        <input ref="txt" type="text" name="" id=""/>
        <button onClick={
     this.handleClick}>按钮</button>
      </div>
    )
  }
}

此时我们已经成功创建了一个ref,但是因为我们并没有进行绑定某个元素,所以目前它为空
react学习—ref_第7张图片

import React, {
      Component } from 'react'


export default class Comp extends Component {
     
  constructor(props) {
     
    super(props);
    this.txt = React.createRef();
    console.log(this.txt);
  }
  render() {
     
    return (
      <div>
        <input ref={
     this.txt} type="text" name="" id=""/>
        <button onClick={
     this.handleClick}>按钮</button>
      </div>
    )
  }
}

当我们帮顶了input元素后,render时就会对txt赋值。
react学习—ref_第8张图片

import React, {
      Component } from 'react'


export default class Comp extends Component {
     
  constructor(props) {
     
    super(props);
    this.txt = React.createRef();
    console.log(this.txt);
  }
  handleClick = () => {
     
    console.log(this);
    this.txt.current.focus();
    console.log('input获取焦点');
  }
  render() {
     
    return (
      <div>
        <input ref={
     this.txt} type="text" name="" id=""/>
        <button onClick={
     this.handleClick}>按钮</button>
      </div>
    )
  }
}

使用时,由于是一个对象,所以要以对象属性的方式调用。
react学习—ref_第9张图片
以下的书写方式也是毫无问题的

constructor(props) {
     
    super(props);
    this.txt = {
     
      current: null
    };
    console.log(this.txt);
  }

4、ref使用函数

1.行间函数

import React, {
      Component } from 'react'


export default class Comp extends Component {
     
  handleClick = () => {
     
    this.txt.focus();
    console.log('input获取焦点');
  }
  render() {
     
    return (
      <div>
        <input ref={
     el => {
     
          console.log('ref函数');
          this.txt = el;
        }} type="text"/>
        <button onClick={
     this.handleClick}>按钮</button>
      </div>
    )
  }
}

那么该函数是如何执行,何时执行的呢?
react学习—ref_第10张图片

export default class Comp extends Component {
     
  handleClick = () => {
     
    this.txt.focus();
    console.log('input获取焦点');
  }
  componentDidMount() {
     
    console.log("didMount", this.txt);
  }
  render() {
     
    return (
      <div>
        <input ref={
     el => {
     
          console.log('ref函数');
          this.txt = el;
        }} type="text" />
        <button onClick={
     this.handleClick}>按钮</button>
      </div>
    )
  }
}

实际上ref函数会在componentDidMount生命周期时自动执行赋值。
react学习—ref_第11张图片

export default class Comp extends Component {
     
  handleClick = () => {
     
    this.txt.focus();
    this.setState({
     });
    console.log('input获取焦点');
  }
  componentDidMount() {
     
    console.log("didMount", this.txt);
  }
  render() {
     
    return (
      <div>
        <input ref={
     el => {
     
          console.log('ref函数',el);
          this.txt = el;
        }} type="text" />
        <button onClick={
     this.handleClick}>按钮</button>
      </div>
    )
  }
}

一旦组件状态发生改变,组件重新渲染,发现我们的ref函数执行了两次,因为这个函数是写在行间的,每次渲染都会触发。
react学习—ref_第12张图片

2.声明调用

行间函数形式,会因为页面重新先渲染导致ref函数重新执行,我们就可以用函数保存,然后每次直接调用同一个函数。

import React, {
      Component } from 'react'


export default class Comp extends Component {
     
  handleClick = () => {
     
    this.txt.focus();
    this.setState({
     });
    console.log('input获取焦点');
  }
  componentDidMount() {
     
    console.log("didMount", this.txt);
  }
  getRef = el => {
     
    console.log("ref函数", el);
    this.txt = el;
  }
  render() {
     
    return (
      <div>
        <input ref={
     this.getRef} type="text" />
        <button onClick={
     this.handleClick}>按钮</button>
      </div>
    )
  }
}

此时就能看到,我们的ref函数并没有因为状态改变而重新执行。
react学习—ref_第13张图片
此外,组件卸载时,也会执行ref函数。(即ref以来的元素变化了,ref函数就会执行)

import React, {
      Component } from 'react'


export default class Comp extends Component {
     
  state = {
     
    show: true
  }
  handleClick = () => {
     
    this.setState({
     
      show: !this.state.show
    });
  }
  componentDidMount() {
     
    console.log("didMount", this.txt);
  }
  getRef = el => {
     
    console.log("ref函数", el);
    this.txt = el;
  }
  render() {
     
    return (
      <div>
        {
     
          this.state.show && <input ref={
     this.getRef} type="text" />
        }
        <button onClick={
     this.handleClick}>显示/隐藏</button>
      </div>
    )
  }
}

组件被卸载,ref函数触发。
react学习—ref_第14张图片
总结:

  1. componentDidMount的时候会调用该函数
    1. 在componentDidMount事件中可以使用ref
  2. 如果ref的值发生了变动(旧的函数被新的函数替代),分别调用旧的函数以及新的函数,时间点出现在componentDidUpdate之前
    1. 旧的函数被调用时,传递null
    2. 新的函数被调用时,传递对象
  3. 如果ref所在的组件被卸载,会调用函数

谨慎使用ref

能够使用属性和状态进行控制,就不要使用ref。

  1. 调用真实的DOM对象中的方法
  2. 某个时候需要调用类组件的方法

你可能感兴趣的:(react学习,react)