为什么获取createRef的结果需要多一层current呢?

<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拿呢?

阅读 2.7k
3 个回答

这个问题看起来很深奥,但是其实很基础。而且由于你使用了类组件写法所以遮盖了很多东西。

回到普通的场景一下子就清楚了:

const isRef = React.createRef();

如你所说,不使用isRef.current,你怎么给isRef赋值? const不行改let? 但是本质没变啊,只要你给isRef赋值,它就不是React.createRef()了。理解了?

已参与了 SegmentFault 思否社区 10 周年「问答」打卡 ,欢迎正在阅读的你也加入。

因为ref的内容是可变的,你传给input的是this.myRef1,而input接收到的只是一个十分普通的object,即input组件不知道这个对象是哪里来的,只知道有东西进来了,所以没有办法对这个对象进行替换操作。

唯一通用的方式就是再包一层,外层通用,里层业务

js中基础概念介绍

其实想要理解为什么多一层current,那么需要理解下JS中的基本数据引用数据。我们先从基本数据来开始理解:
定义一个变量,它的名称叫做:baseType

let baseType = 10

后续的操作中,改变了变量baseType中的数据

baseType = 20

那么这时候变量baseType的内存指向其实已经变成内存中20这个值的具体地址了。
如果是一个引用数据呢?
定义一个变量,它的名字叫做:referencedType

let referencedType = {
    a: 10
}

后续操作中改变了变量referencedTypea字段的值并且新增一个字段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的回答

如果理解了上述中基本类型和引用类型的概念。那么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绑定的丢失。

打完收功...

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题