<input ref={this.myRef1} type="text" placeholder='点击提示createRef'/>
this.myRef1= React.createRef()
获取input的值:console.log(this.myRef1.current.value)
一直搞不明白这个API的设计,这里要多一层current是什么用意,难道除了current外还有别的用法吗?如果只有获取值的用法,为什么不直接简化成this.myRef1.value拿呢?
<input ref={this.myRef1} type="text" placeholder='点击提示createRef'/>
this.myRef1= React.createRef()
获取input的值:console.log(this.myRef1.current.value)
一直搞不明白这个API的设计,这里要多一层current是什么用意,难道除了current外还有别的用法吗?如果只有获取值的用法,为什么不直接简化成this.myRef1.value拿呢?
因为ref的内容是可变的,你传给input的是this.myRef1
,而input接收到的只是一个十分普通的object
,即input组件不知道这个对象是哪里来的,只知道有东西进来了,所以没有办法对这个对象进行替换操作。
唯一通用的方式就是再包一层,外层通用,里层业务
其实想要理解为什么多一层current
,那么需要理解下JS
中的基本数据
和引用数据
。我们先从基本数据来开始理解:
定义一个变量,它的名称叫做:baseType
let baseType = 10
后续的操作中,改变了变量baseType
中的数据
baseType = 20
那么这时候变量baseType
的内存指向其实已经变成内存中20
这个值的具体地址了。
如果是一个引用数据呢?
定义一个变量,它的名字叫做:referencedType
let referencedType = {
a: 10
}
后续操作中改变了变量referencedType
中a
字段的值并且新增一个字段b
referencedType.a = 20
referencedType.b = 'my name is b'
执行了上述操作,并没有改变变量referencedType
的内存指向,改变的只是变量referencedType
中其他字段的值。
如果想要改变变量referencedType
的内存指向,该怎么处理?其实就是给该变量赋值一个新的内存地址即可。
// 我们先将变量referencedType已有的内存地址赋值给一个新的变量
let newReferenced = referencedType;
// 再改变变量referencedType的内存地址
referencedType = {a: 20, b: 'my name is b'}
// 将两个变量进行对比
console.log(newReferenced === referencedType) // 输出false
如果理解了上述中基本类型和引用类型的概念。那么createRef
为什么多一层current
的答案其实就在上述的回答中。
当我们给一个DOM
节点绑定ref
的时候,该语法是这样的
function TestRef() {
const ref = React.useRef()
return (
<div ref={ref}>
// 其他业务逻辑...
</div>
)
}
export default TestRef
那么在react
中,ref
的绑定大致可以这样描述(只是伪代码,不可较真):
const ref = {current: void 0}
function TestRef() {
ref.current = new HTMLDivElement()
}
如果 TestRef
这个组件内部有 useState
的操作,那么就会触发render
函数的重新执行。可以这样理解:
// 触发了一次 useState操作,执行一次TesetRef方法
TestRef()
// 又触发了一次 useState操作,又执行了一次TestRef方法
TestRef()
....
所以,每当render
重新渲染,我们拿到的其实都是一个新的DOM
对象,那么也就是一个新的内存地址。这就是为什么会多一层current
的原因。如果没有这一层current
,那么在render
更新的时候就会导致ref
绑定的丢失。
打完收功...
10 回答11.1k 阅读
5 回答4.8k 阅读✓ 已解决
4 回答3.1k 阅读✓ 已解决
2 回答2.7k 阅读✓ 已解决
3 回答5.1k 阅读✓ 已解决
3 回答1.9k 阅读✓ 已解决
4 回答2.5k 阅读✓ 已解决
这个问题看起来很深奥,但是其实很基础。而且由于你使用了类组件写法所以遮盖了很多东西。
回到普通的场景一下子就清楚了:
如你所说,不使用isRef.current,你怎么给isRef赋值?
const
不行改let
? 但是本质没变啊,只要你给isRef赋值,它就不是React.createRef()了。理解了?已参与了 SegmentFault 思否社区 10 周年「问答」打卡 ,欢迎正在阅读的你也加入。