ref的三种使用方法

ref

ref属性可以帮助我们获取子组件的实例或者DOM对象,进而对子组件进行修改。

使用场景: 希望直接使用dom元素中的某个方法,或者希望直接使用自定义组件中的某个方法。

ref的注意事项

  1. ref作用域内置的html组件,得到的将是真实的dom对象

  2. ref作用域类组件,得到的将是类的实例

  3. ref不能直接作用于函数组件,但是可以使用ref转发和HOOK使用ref

    不论是在函数里面使用,还是使用函数组件的标签,都不可以使用ref

     function CompB(props) {
         function handleFunClick() {
             console.log('CompB', props);
         }
         return (
             <>
                 <h1 refs="h1">我是函数组件B</h1>
                 <button onClick={handleFunClick}>函数组件CompB</button>
             </>
         )
     }
     render() {
             return (
                 <>
                     <CompB ref="CompB" />
                 </>
             );
         }
    复制代码

ref的写法

  1. 字符串式写法(不被推荐使用)

    由于效率问题被不推荐,并且不灵活

 <input ref="text" type="text" />  
 <CompA ref="CompA" />
 ​
复制代码

调用:

 this.refs.text
复制代码
  1. 对象使写法

React.createRef()

React.createRef()会创建一个对象,在这个对象里面有一个current属性,用来保存DOM元素或者实例对象。这时输出的所创建对象得到的DOM元素对象或者实例中的refs中的值是空

每创建一个,如:this.text 只能控制一个DOM元素或者实例对象,这是由于 current 没有被设计成对象 / 数组无法保存多个DOM元素或实例对象

React.createRef() 在render的时候赋值,遇到了jsx对象中有使用 React.createRef() 的就会进行赋值

 class NewRef extends Component {
     constructor(props) {
         super(props);
         this.text = React.createRef();
         this.text = {// 可以自己写一个 createRef() 函数,这就是其返回值
             current: null
         };
         console.log(this.text);
     }
 ​
     handleFocus= () => {
         console.log(this);
         this.text.current.focus();
     }
     
     render() {
         return (
             <>
                 <input ref={this.text} type="text" />   
                 <input ref={this.text} type="text" />   
                 <input ref={this.text} type="text" />   
                 <input ref={this.text} type="text" />   
                 <p ref={this.text}>123123</p>   
                 <button onClick={this.handleFocus}>聚焦</button>
             </>
         );
     }
 }
复制代码
  1. 函数形式写法

函数式写法就是在React元素或者组件上面直接添加一个函数,这时输出的所创建对象得到的DOM元素对象或者实例中的refs中的值是空。

 <input ref={el => {
     this.text = el;
     console.log('查看el的状态', el);
 }} type="text" />
复制代码

函数中的参数(el) 代表的是DOM对象或者实例,react自动会传入的一个,无需自己传入;this.text 就是ref 的名字。

渲染调用

如果在元素的行内式中加上函数,那么在渲染之后会重复调用两次。

 class FunRef extends Component {
     handleFocus = () => {
         this.text.focus();
         this.setState({})
     }
     render() {
         return (
             <div>
                 <input ref={el => {
                     this.text = el;
                     console.log('查看el的状态', el);
                 }} type="text" />
                 {/* <input ref={el => {
                     this.text = el;
                     console.log('查看el的状态', el);
                 }} type="text" /> */}
                 <button onClick={this.handleFocus}>点击聚焦</button>
             </div>
         );
     }
 }
复制代码

每当点击按钮聚焦的时候,使用setState会引起render重新渲染,导致行内式函数会调用两次,第一次输出的el的值是null,第二次输出的值是ref绑定的值。并且在页面加载之后就会发生一次调用ref函数。

react-funref.png

这样就会导致,ref函数无法跟踪到值的改变,当时可以进行一些与值无关的操作。这样每次执行render就会重新调用一次函数,函数的值一直都是原来的值,已发生改变就会调用一个新的函数,那么怎么做可以改变这一现象呢?

其实只要在render外部调用这个函数即可,这样每次render调用的函数只会是这个外部的函数,函数的引用地址不会发生改变,并且外部函数的引用没有发生任何变化,所以函数也不会重复的执行。这样无论如何点击,都不会输出,因为在页面加载的时候已经调用过了这个函数。

 class FunRef extends Component {
     handleFocus = () => {
         // console.log(this);
         this.text.focus();
         this.setState({})
     }
     handleRefFun = el => {
         this.text = el;
         console.log('查看el的状态', el);
     }
     render() {
         return (
             <div>
                 <input ref={this.handleRefFun} type="text" />
                 {/* <input ref={el => {
                     this.text = el;
                     console.log('查看el的状态', el);
                 }} type="text" /> */}
                 <button onClick={this.handleFocus}>点击聚焦</button>
             </div>
         );
     }
 }
复制代码

ref调用时间

  1. componentDidMount的时候会调用该函数

    1. 在componentDidMount事件中可以使用ref
  2. 如果ref的值发生了变动(就的函数被新的函数替代),分别调用旧的函数以及新的函数,时间点出现在componentDidUpdate之前

    1. 旧的函数被调用时,传递null
    2. 新的函数被调用时,传递对象(dom元素对象或者实例对象)
  3. 如果ref所在的组件被卸载,会调用函数

关注我一周带你看一篇对你有帮助的干货!!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享