react学习—ref

一、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元素。
在这里插入图片描述
我们查看输出的this就知道,ref中就有了我们设置的txt标记。
在这里插入图片描述
注意:ref并不是一个属性哦
在这里插入图片描述
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的信息了。
在这里插入图片描述
甚至通过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>
    )
  }
}

在这里插入图片描述
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不能作用于函数组件
在这里插入图片描述
到此为止,是不是觉得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,但是因为我们并没有进行绑定某个元素,所以目前它为空
在这里插入图片描述

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赋值。
在这里插入图片描述

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>
    )
  }
}

使用时,由于是一个对象,所以要以对象属性的方式调用。
在这里插入图片描述
以下的书写方式也是毫无问题的

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>
    )
  }
}

那么该函数是如何执行,何时执行的呢?
在这里插入图片描述

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生命周期时自动执行赋值。
在这里插入图片描述

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函数执行了两次,因为这个函数是写在行间的,每次渲染都会触发。
在这里插入图片描述

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函数并没有因为状态改变而重新执行。
在这里插入图片描述
此外,组件卸载时,也会执行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函数触发。
在这里插入图片描述
总结:

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

谨慎使用ref

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

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

博主开始运营自己的公众号啦,感兴趣的可以关注“飞羽逐星”微信公众号哦,拿起手机就能阅读感兴趣的博客啦!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞羽逐星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值