弄懂 React 的 ref,理解 React 的实例与 vDom 之间的关系

React 的 ref

最近公司来了一个新人,然后在使用 ref 的时候,碰到了一些问题,帮她解答后现在拿出来分享一下。

当你给组件H5标签添加 ref 属性后,此实例只能在当前组件中被访问到,父组件的 refs 中是没有此引用的,例如:

import React, { Component } from 'react'
import { render } from 'react-dom'
import util from './lib/util'
export default class Father extends Component {

  componentDidMount () {
    console.log( this.refs['child-h1'] ) // => undefined
  }

  render () {
    
    return 
} } class ChildComponent extends Component { componentDidMount () { console.log( this.refs['child-h1'] ) // => h1 可以拿到这个 h1 } render () { return

我是子组件

} } render(, document.getElementById("root"))

从上面例子,就可以知道 React 的 ref 只针对本组件有效,那如果我想使用父组件访问子组件的 ref 怎么办?看例子:

import React, { Component } from 'react'
import { render } from 'react-dom'
import util from './lib/util'
export default class Father extends Component {

  componentDidMount () {
    console.log( this.refs['child-h1'] ) // => undefined
    console.log( this.refs['child-component'].refs['child-h1'] ) // => h1 可以拿到这个 h1  
    }

  render () {
    
    return 
} } class ChildComponent extends Component { componentDidMount () { console.log( this.refs['child-h1'] ) // => h1 可以拿到这个 h1 } render () { return

我是子组件

} } render(, document.getElementById("root"))

而细心的小伙伴就会发现,这边我们的 ref 指向的是一个 React 组件,不是 h5 标签。我们都知道给 h5 元素设置 ref 后,我们可以拿到它的真实 dom,那如果我们给 React 组件 加了一个 ref,考虑过会得到什么吗?虚拟 dom?其实并不是,我们拿到是 React 组件 的实例,这和 vDom 有什么差别?我相信很多人会疑惑这个,下面我们就介绍一波

React 的实例与 vDom(虚拟 dom)之间的关系

首先我们都知道 vDom 是 React 的一大创举,一句话概括来说就是使用 js 的对象来构建一个,结构树和 dom 的结构一样的对象,一个 div 的 vDom 样子长:

| ∨ { Symbol(react.element) ,key: null ,props: {children: " "} ,ref: null ,type: "div" ,_owner: ReactCompositeComponentWrapper {_currentElement: {…}, _rootNodeID: 0, _compositeType: 0, _instance: MyTest, _hostParent: ReactDOMComponent, …} ,_store: {validated: false} ,_self: null ,_source: null ,__proto__: Object }

我慢把那些干扰变量拿掉,重要的东西有

| ∨ { props: {children: ''} ,type: 'div' }

是不是已经理解了 vDom 了?我们在来写有子元素的,你就更明白了

我是子元素

| ∨ { props: {children: { props: {children: “我是子元素”} ,type: 'h1' }} ,type: 'div' }

加个 props

我是子元素

| ∨ { props: {children: { props: {children: “我是子元素”, id: 'id1'} ,type: 'h1' }} ,type: 'div' }

好了,vDom 是什么我们已经知道了,那么 react 从哪儿创建这些 dom 的呢?其实也就是你写的 React 组件里 render 的返回值,就是这些 vDom

export default class MyTest extends Component {

  render () {
    const vDom = 

我是子元素

console.log( vDom ) // 去控制台上看,就可以看到 return vDom } }

这里使用了 jsx 语法所以不清晰,翻译成原生 js 就是:

我是子元素

| ∨ React.createElement( 'div', null, React.createElement( 'h1', null, '我是子元素' ) );

React.createElement 接受了三个参数进行创建,vDom 至于具体实现,我们这边就不接受了不是今天的话题

有人可能要急了,讲了半天怎么还没讲 React 组件的实例和 vDom 直接的关系,但是其实你看完上面的这些解释就已经大概明白了,只不过差一点火候。

我们都知道,我们在写 React 组件的时候:

  • 必须继承于 React.Component(es6)
  • 必须有 render 函数

当你入口 render 被执行,也就是下面代码

render(, document.getElementById("root"))

首先会去 new 一个 Father 这个组件,也就是你写的

class Father extends Component {

  componentDidMount () {
    console.log( this.refs['child-h1'] ) // => undefined
  }

  render () {
    
    return 
} }

这就是 Father 组件的实例,然后再会调用此实例的方法 render 进行 vDom 的创建。

所以当你在在一个组件上使用 ref 的时候,我们可以拿到的就是它的实例,也就是:

class Father extends Component {

  componentDidMount () {
    console.log( this.refs['childC'] ) // 兄弟,我就是实例
  }

  render () {
    
    return 
} } class ChildComponent extends Component { componentDidMount () { console.log( this ) // 兄弟,我就是实例哦 我等于我父组件的 this.refs['childC'] } render () { return
我是子组件
} }

ref 的回调写法,直接拿到实例

class Father extends Component {

  render () {
    
    return 
{ console.log( childItem ) // 我是实例哦 }}>
} } class ChildComponent extends Component { componentDidMount () { console.log( this ) // 兄弟,我就是实例哦 } render () { return
我是子组件
} }

如果觉得有帮助,请帮忙点下赞哦,非常感谢

我的:

  • gitHub: https://github.com/gwiron
  • blog: http://www.jianshu.com/u/b40d6be41fa2

你可能感兴趣的:(弄懂 React 的 ref,理解 React 的实例与 vDom 之间的关系)