所想如愿 發表於 2019-11-26 20:24:00

React源码 React ref

<div>ref&nbsp;的功能,在&nbsp;react&nbsp;当中。我们写了一个组件,在这个时候,我们的&nbsp;render&nbsp;function&nbsp;里面我们会渲染一系列的子组件或者&nbsp;dom&nbsp;节点,有时候我们会希望有这样的需求,就是我们要获取某个&nbsp;dom&nbsp;节点,或者是某个子组件的实例。去对他进行一些手动的操作,而不仅仅是&nbsp;props&nbsp;更新这种方式去更新这个节点。比如我们要获取一个&nbsp;dom&nbsp;节点,自己去绑定某一些事件,然后去做一些操作。通过&nbsp;ref&nbsp;这个特殊的&nbsp;attr&nbsp;非常方便的在组件内部去获取到子节点的具体的一个实例。这就是&nbsp;ref&nbsp;的核心功能。</div>
<p>&nbsp;</p>
<div>代码</div>
<div>
<div class="cnblogs_code">
<pre>import React from 'react'<span style="color: rgba(0, 0, 0, 1)">

export </span><span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)"> class RefDemo extends React.Component {
constructor() {
    super()
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.objRef =<span style="color: rgba(0, 0, 0, 1)"> React.createRef()
}

componentDidMount() {
    setTimeout(() </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.refs.stringRef.textContent = 'string ref got'
      <span style="color: rgba(0, 0, 255, 1)">this</span>.methodRef.textContent = 'method ref got'
      <span style="color: rgba(0, 0, 255, 1)">this</span>.objRef.current.textContent = 'obj ref got'<span style="color: rgba(0, 0, 0, 1)">
    }, </span>1000<span style="color: rgba(0, 0, 0, 1)">)
}

render() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
      </span>&lt;&gt;
      &lt;p ref="stringRef"&gt;span1&lt;/p&gt;
      &lt;p ref={ele =&gt; (<span style="color: rgba(0, 0, 255, 1)">this</span>.methodRef = ele)}&gt;span3&lt;/p&gt;
      &lt;p ref={<span style="color: rgba(0, 0, 255, 1)">this</span>.objRef}&gt;span3&lt;/p&gt;
      &lt;/&gt;
<span style="color: rgba(0, 0, 0, 1)">    )
}
}</span></pre>
</div>
<p>&nbsp;</p>
</div>
<p>&nbsp;</p>
<div>如上,在&nbsp;react&nbsp;当中有3中使用&nbsp;ref&nbsp;的方式</div>
<div>1、<strong>string&nbsp;ref&nbsp;</strong></div>
<div>
<div class="cnblogs_code">
<pre>&lt;p ref="stringRef"&gt;span1&lt;/p&gt;
=&gt;
<span style="color: rgba(0, 0, 255, 1)">this</span>.refs.stringRef.textContent = 'string ref got'</pre>
</div>
<p>也就是我们想要获取的这个节点的&nbsp;props&nbsp;上面使用一个&nbsp;ref&nbsp;属性,然后传入一个字符串,传入这个字符串之后呢,react&nbsp;在完成这一个节点的渲染之后,他会在&nbsp;this.refs&nbsp;这个对象上面挂载这个&nbsp;string&nbsp;对应的一个&nbsp;key&nbsp;。那么这个&nbsp;key&nbsp;他所指向的就是我们这个节点他的实例的对象。如果是&nbsp;dom&nbsp;节点,他就对应&nbsp;dom&nbsp;的实例,如果是子组件就会是子组件的实例,就是我们的&nbsp;class&nbsp;component。如果是&nbsp;function&nbsp;component&nbsp;怎么办呢,正常来讲,他是会失败的,也就是拿到的会是个&nbsp;undefined&nbsp;。因为&nbsp;function&nbsp;component&nbsp;没有实例。这是第一种使用的方式,也是&nbsp;v16&nbsp;之前用的最多的方式。也是最不被推荐的一种方式。在下一个大版本之中会被废弃的一种方式</p>
</div>
<p>&nbsp;</p>
<div>2、<strong>function</strong>&nbsp;</div>
<div>
<div class="cnblogs_code">
<pre>&lt;p ref={ele =&gt; (<span style="color: rgba(0, 0, 255, 1)">this</span>.methodRef = ele)}&gt;span2&lt;/p&gt;
=&gt;
<span style="color: rgba(0, 0, 255, 1)">this</span>.methodRef.textContent = 'method ref got'</pre>
</div>
<p>这个我们的&nbsp;ref&nbsp;传入的是一个方法,这个方法会接收一个参数,这个参数就是这个节点对应的实例,如果是&nbsp;dom&nbsp;节点对应的是&nbsp;dom&nbsp;的实例,如果是组件对应的是组件的实例。然后我们可以自己去this上面去挂载某一个属性,比如在这里,对应的是&nbsp;methodRef&nbsp;。</p>
</div>
<p>&nbsp;</p>
<div>3、<strong>createRef</strong>&nbsp;(这是&nbsp;react&nbsp;提供给我们的&nbsp;api)</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">this</span>.objRef =<span style="color: rgba(0, 0, 0, 1)"> React.createRef()
这个 api 就是 React.createRef(),这个对象其实就是这样的 { current: </span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)"> } 。然后这个对象传入给某一个节点
</span>&lt;p ref={<span style="color: rgba(0, 0, 255, 1)">this</span>.objRef}&gt;span3&lt;/p&gt;</pre>
</div>
<p>在组件渲染完成之后,会把这个节点对应的实例挂载到这个对象的&nbsp;current&nbsp;这个属性里面,我们要调用他就是通过</p>
</div>
<div>this.objRef.current.textContent&nbsp;=&nbsp;'obj&nbsp;ref&nbsp;got'</div>
<p>&nbsp;</p>
<div>运行这个js文件,显示&nbsp;span1&nbsp;span2&nbsp;span3&nbsp;。一秒钟后被&nbsp;string&nbsp;ref&nbsp;got&nbsp;,&nbsp;method&nbsp;ref&nbsp;got,&nbsp;obj&nbsp;ref&nbsp;got&nbsp;替换。然后我们看&nbsp;createRef&nbsp;这个的源码,因为其他的两种方式并没有在源码上有任何的体现,因为他们传入的一个是&nbsp;string&nbsp;,一个&nbsp;function&nbsp;。并没有直接挂载到&nbsp;React&nbsp;上面的一个&nbsp;api。只有第三种方式&nbsp;React.createRef&nbsp;给我们创建了这么一个东西。</div>
<p>&nbsp;</p>
<div>我们看&nbsp;React.js&nbsp;里面&nbsp;createRef&nbsp;引自&nbsp;ReactCreateRef</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* @flow
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">

import type {RefObject} from </span>'shared/ReactTypes'<span style="color: rgba(0, 0, 0, 1)">;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> an immutable object with a single mutable value</span>
export <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> createRef(): RefObject {
const refObject </span>=<span style="color: rgba(0, 0, 0, 1)"> {
    current: </span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,
};
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (__DEV__) {
    Object.seal(refObject);
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> refObject;
}</span></pre>
</div>
</div>
<p>点开源码,震惊了,非常的少。&nbsp;也非常的简单,他返回的就是这样一个对象&nbsp;refObject&nbsp;。他里面&nbsp;current&nbsp;是&nbsp;null&nbsp;。如果是开发状态下&nbsp;Object.seal(refObject)&nbsp;。refObject&nbsp;这个对象被封闭,阻止添加新属性并将现有属性标记为不可配置。当前属性的值只要可写就可以改变</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/wzndkj/p/11938192.html
頁: [1]
查看完整版本: React源码 React ref