上节课我们开始了react
组件三大属性的最后一个属性refs
的学习,上节课呢我们学习的是字符串类型的ref
,以及ref
在事件处理方面的应用。但是ref
其实并不仅仅只有字符串形式。
那么今天,我们来学习一下关于回调形式的ref
的运用
回顾
refs
是一个收集各个标签ref
属性来作为标识的一个对象refs
可以代替document.getElementById
方法来获取页面节点refs
可以配合事件处理来完成相应的功能需求。
以上便是上节课的知识要点,接下来我们开始正式学习回调形式的ref
概述
上节课中我们学习的是字符串类型的ref
,但是有一点其实官方呢已经不推荐使用字符串类型的ref
了,而且官方明确表示,在后期的新版本更新中可能将把字符串形式的ref
就废弃掉了。或许大家会说,那我上节课学了那么半天不是玩儿呢嘛。咱别这么说,万一咱接手了一个旧版本的项目那还是得会这个的。而且面试的时候相关的知识也得用啊。准我们不用,但是你不能不会啊。
但是为啥不不建议使用字符串类型的ref
呢?我们来看一下官方文档:
官方文档告诉我们,字符串类型的refs
存在一些问题。具体是什么问题?我们点击这个链接看一下:
可能有人会说我看不懂。这是直接跳转到GitHub
上了,我们这里也不去详细解释了,就简单概括一下,就是说,字符串类型的refs
在效率方面有问题。也就是说如果字符串类型的refs
用多了,那么就会拖慢整个项目的运行效率。所以说react
官方已经不推荐使用字符串类型的refs
。
回调形式的refs
那行吧,既然官方不推荐了,那就不用呗,那我们用什么呢?官方其实推荐我们使用回调形式或者creatRef API
但是回调形式的refs
应该怎么用呢?我们在代码中分析一下:
class Demo extends React.Component { render() { return ( <div> <input type="text" placeholder="click the button" /> <button onClick={this.showData}>Click me</button> <input onBlur={this.bulrData} type="text" placeholder="lose focus" /> </div> ); } showData = () => { } bulrData = () => { } }
我们看上面这段代码,我们现在都还没有加ref
属性,所以说我们目前也不知道该怎么编写showData
和blurData
这两个方法,先不着急,我们说要写回调形式的ref
是什么意思呢?没有什么绕弯子的意思,很直白,就是ref
是一个回调函数呗,那么我们先给其中一个input
标签加一个ref
吧:
class Demo extends React.Component { render() { return ( <div> <input ref={() => {}} type="text" placeholder="click the button" /> ... </div> ); } ... }
上面这段代码我们给ref
设定的值是一个箭头函数。但是这个是回调函数吗?怎么判断一个函数是不是回调函数?是不是有三个特点?
- 我们自定义的函数
- 我们自己没有调用
- 最终函数被执行了
那我们看一下,这是我们定义的,而且我们定义之后确实没有调用,但是这个函数最终执行了吗?那我们打印一下看看:
class Demo extends React.Component { render() { return ( <div> <input ref={() => {console.log("call the func");}} type="text" placeholder="click the button" /> ... </div> ); } ... }
看一下效果吧:
控制台有输出,看来是成功调用了。那么这个不用说就是一个回调函数。但是这个回调函数会收到什么参数呢?这个是不是取决于这个回调函数的调用者?而且这个回调函数到底接没接到参数?就算接到了,接到的是什么啊?那我们再打印一下看看就知道了啊
class Demo extends React.Component { render() { return ( <div> <input ref={(a) => {console.log(a);}} type="text" placeholder="click the button" /> ... </div> ); } ... }
我们用a
来接一下参数然后把参数打印出来:
诶,我们看到了我们所接到的就是这个这个加了ref
属性的标签节点。
然后大家又开始发散思维了,我们之前字符串的refs
调用的时候this.refs.input1
得到的就是这个ref="input1"
所在的标签,那么我们这里的回调函数里面是不是return a
就行了呢?
我们来看一下:
class Demo extends React.Component { render() { return ( <div> <input ref={(a) => {return a;}} type="text" placeholder="click the button" /> <button onClick={this.showData}>Click me</button> <input onBlur={this.bulrData} type="text" placeholder="lose focus" /> </div> ); } showData = () => { console.log(this); } bulrData = () => { } }
我们先来在点击事件里面打印一下this
看看:
这是为什么?为什么我们在回调函数里面返回了接到的参数refs
却没有收集呢?这个收集是不是我们在字符串ref
那一节说的?这里不是字符串ref
啊,那肯定就不支持这种方法了。而且跟你有没有return
没有关系,因为这个是定义一个回调函数又不是定义一个函数并获取返回值。
退一万步来说:ref={ () => {} }
,这是不是相当于ref=function
,按照字符串ref
的规则,是不是应该收集function: DOM
然后存放到this.refs
里面?这是一对key-value
,但是大家有谁见过拿一个函数做key
的?
大家看这是不是报错了?所以说只要ref
属性不是字符串,那就默认不收集到this.refs
。
那我们来说一下这个回调函数应该怎么写:
class Demo extends React.Component { render() { return ( <div> <input ref={(a) => {this.input1 = a;}} type="text" placeholder="click the button" /> ... </div> ); } showData = () => { } bulrData = () => { } }
我们在回调函数中把a
赋值给this.input1
但是这是什么意思呢?react
要想渲染页面就得实例化我们的Demo
组件,然后再通过Demo
的实例来调用render
,那调用render
方法就一定会执行render
方法中的jsx
代码,那么就一定会触发ref
的这个回调函数的执行。
在看我们这个回调函数,代码层面上说,我们的目的是不是只要一执行就把传进去的标签节点放到实例自身的input1
属性上?
但是,我来问大家,这个回调函数是谁调的?我们是不是从始至终都不太确定啊?我们只是知道了这个回调函数接到了什么参数,至于这个参数是谁传的?不确定,那这个回调函数有this
吗?
在state
的简写那一节我们就说过箭头函数没有自己的this
,但是如果在箭头函数中使用this
关键字的话,会自动往箭头函数的外层去寻找,那么这里的this
指向是什么?是不是组件的实例对象。以为这个回调函数的外层是render
方法,render
方法是react
通过Demo
组件的实例调用的,那么render
方法中的this
指向的就是组件的实例对象啊。
也就是说我们其实是达到了我们的目的了,我们确实成功地将标签节点放在了实例自身的input1
属性上。那么我们在改一下代码:
class Demo extends React.Component { render() { return ( <div> <input ref={c => this.input1 = a;} type="text" placeholder="click the button" /> ... </div> ); } showData = () => { alert(this.input1.value); } bulrData = () => { } }
这下我们不从refs
里面取value
了,我们直接从this.input1
上取。看一下结果:
一切正常。那么另一个标签是不是也就照方抓药?
class Demo extends React.Component { render() { return ( <div> <input ref={c => this.input1 = c} type="text" placeholder="click the button" /> <button onClick={this.showData}>Click me</button> <input ref={c => this.input2 = c} onBlur={this.bulrData} type="text" placeholder="lose focus" /> </div> ); } showData = () => { alert(this.input1.value); }; bulrData = () => { alert(this.input2.value); } }
再看一下效果:
我们看一下,是不是也正常实现功能了啊?
以上便是这节课的主要内容。
总结
- 回调式
refs
不会自动收集到this.refs
中 - 字符串式
refs
有问题,后期可能会废弃 - 回调式
refs
所传入的ref
属性是一个回调函数 - 回调式
refs
是将传入的标签节点传入回调函数,并通过回调函数将标签节点挂在实例自身
Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.
Link of this article:https://work.lynchow.com/article/callback_refs/