这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战
1. 字符串形式的ref
首先这种形式是不推荐使用的。
过时 API:String 类型的 Refs:
如果你之前使用过 React,你可能了解过之前的 API 中的 string 类型的 ref 属性,例如 "textInput"
。你可以通过 this.refs.textInput
来访问 DOM 节点。我们不建议使用它,因为 string 类型的 refs 存在一些效率上的问题。它已过时并可能会在未来的版本被移除(16.8版本还没有移除)。
点击按钮获取输入框数据
按照我们原生的写法,怎么在函数中获得输入框中的内容呢?首先给输入框一个id,然后通过getElementById 获得输入框中的值。
class Demo extends React.Component{
showData = ()=>{
let value = document.getElementById('input1').value
console.log(value)
}
render(){
return(
<div>
<input type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点击提示数据</button>
<input type="text" placeholder="失去焦点提示数据" />
</div>
)
}
}
但是在React中去使用原生不是很好。因此ref就出现了。给input标签中添加ref属性(就类似于id)
此时输出的this是类的实例 。 我们发现了refs中有 input1,是键值对类型。
打印、获取输入框的内容
showData = ()=>{
console.log(this.refs.input1.value)
const {input1} = this.refs
}
失去焦点提示数据
<input type="text" ref="input2"
onBlur={this.showData2} placeholder="失去焦点提示数据" />
showData2 =()=>{
const {input2} = this.refs
alert(input2.value)
}
总结
refs 是实例上的属性。ref就像原生js的id,可以理解为打标签。
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import './index.css';
class Demo extends React.Component{
showData = ()=>{
console.log(this.refs.input1.value)
}
showData2 =()=>{
const {input2} = this.refs
alert(input2.value)
}
render(){
return(
<div>
<input ref="input1" type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点击提示数据</button>
<input type="text" ref="input2" onBlur={this.showData2} placeholder="失去焦点提示数据" />
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('root'))
2. 回调形似的ref
ref 中写回调函数,传入的参数是什么呢?我们打印看一下。
<input ref={(a)=>{console.log(a)}} type="text" placeholder="点击按钮提示数据"/>
可以看到打印出来的是ref所处节点
我们接下来把ref所处节点挂载到实例自身上,并取了个名字input1(剪头函数的 this 是其外部的 this,也就是render的实例,也就是 Demo实例)
完整代码:
class Demo extends React.Component{
showData = ()=>{
const {input1} = this
alert(input1.value)
}
showData2 =()=>{
console.log(this)
const {input2} = this
alert(input2.value)
}
render(){
return(
<div>
<input ref={(a)=>{this.input1 = a}} type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点击提示数据</button>
{/* 剪头函数只有一个参数的时候可以简写 */}
<input type="text" ref={c=>this.input2=c} onBlur={this.showData2} placeholder="失去焦点提示数据" />
</div>
)
}
}
回调执行次数问题
关于回调 refs 的说明
如果 ref
回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null
,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。
内联的写法
首先什么是内联函数?如下ref中的函数就是内联函数。
<input ref={(currentNode)=>{this.input1 = currentNode;console.log("currentNode",currentNode)}} type="text" placeholder="点击按钮提示数据"/>
那么什么又算更新过程呢?
我点击按钮输出文本框的内容算吗?这只是交互,并不算是更新。
还记得我们前几篇文章用到的点击按钮切换天气的例子吗?我们在这里再次用到它。也就是用setState的使用。
state = {
isHot:true
}
showInfo = ()=>{
const {input1} = this
alert(input1.value)
}
changeWeather = ()=>{
// 获取原来状态
const {isHot} = this.state
this.setState({isHot:!isHot})
}
render(){
const {isHot} = this.state
return(
<div>
<h1>今天天气很{isHot?"炎热":"凉爽"}</h1>
<input ref={(currentNode)=>{this.input1 = currentNode;console.log("currentNode",currentNode)}} type="text" placeholder="点击按钮提示数据"/><br></br>
<button onClick={this.showInfo}>点击提示数据</button><br></br>
<button onClick={this.changeWeather}>点击改变天气</button><br></br>
</div>
)
}
点击改变天气按钮 我们发现 打印了两次,并且第一次是null,第二次才是节点。(点击改变天气使页面进行了更新)
?
当更新页面时,render方法就会被调用一次。然后<input ref={(currentNode)=>{this.input1 = currentNode;console.log("currentNode",currentNode)}} type="text" placeholder="点击按钮提示数据"/>
代码就会执行,它又会发现ref,而且还是函数式的ref。这个函数又是一个新的函数了,之前的函数被执行完释放了。它并不确定之前的函数执行了什么,因此为了清空上一次调用的函数,传了null将第函数清空,第二次才把当前节点传进来。
怎么解决呢??
class 的绑定函数的写法
通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。 this.saveInput
class Demo extends React.Component{
state = {
isHot:true
}
showInfo = ()=>{
const {input1} = this
alert(input1.value)
}
changeWeather = ()=>{
// 获取原来状态
const {isHot} = this.state
this.setState({isHot:!isHot})
}
saveInput = (c)=>{
this.input1 = c
console.log("c",c)
}
render(){
const {isHot} = this.state
return(
<div>
<h1>今天天气很{isHot?"炎热":"凉爽"}</h1>
{/* <input ref={(currentNode)=>{this.input1 = currentNode;console.log("currentNode",currentNode)}} type="text" placeholder="点击按钮提示数据"/><br></br> */}
<input ref={this.saveInput} type="text" placeholder="点击按钮提示数据"/><br></br>
<button onClick={this.showInfo}>点击提示数据</button><br></br>
<button onClick={this.changeWeather}>点击改变天气</button><br></br>
</div>
)
}
}
现在怎么点击都不会频繁的调用 saveInput 了,因为 saveInput已经放在实例自身了。
当然直接写成内联的也问题不太。内联的写法是比较常见的。
3. CreateRef
使用 createRef API
React.createRef调用后可以返回一个容器,该容器可以存储被ref标识的节点。但是只能存放一个
class Demo extends React.Component{
// React.createRef调用后可以返回一个容器,该容器可以存储被ref标识的节点
myRef = React.createRef()
state = {
isHot:true
}
showData = ()=>{
console.log(this.myRef)
}
render(){
const {isHot} = this.state
return(
<div>
<h1>今天天气很{isHot?"炎热":"凉爽"}</h1>
<input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/><br></br>
<button onClick={this.showData}>点击按钮提示数据</button><br></br>
</div>
)
}
}
打印 myRef
获得节点对应的值
showData = ()=>{
console.log(this.myRef.current.value)
}
但是这种容器,只能存一个。如果有多个节点,那只能声明多个myRef。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!