React Component vs React Element

React Component vs React Element

有這樣的一個問題:javascript

// 方法定義
function add(x, y) {
    return x + y
}

// 方法調用
add(1, 2)

// 組件定義
class Icon extends Component {}

// 組件調用??????
<Icon />

最後的一句<Icon />用專業的詞歸納是什麼操做,組件調用仍是什麼?html

有答「組件聲明」的,有答「組件調用的」,有「組件初始化」的,還有「使用一個組件」的。沒有一個統一的稱呼。形成這樣局面的緣由是不少時候咱們都沒有去詳細的瞭解過JSX和React實際操做之間的抽象層。如今咱們就深刻研究一下這部分知識。java

咱們來看看最基礎的問題,什麼是React?React就是一個用來寫界面的庫。無論React和React的生態有多複雜,最核心的功能就是用來寫界面的。那麼咱們來看看Element,很簡單,可是一個React element描述的就是你想要在界面上看到的。再深刻一點,一個React element就是一個表明了DOM節點的對象。注意,一個React element並非在界面上實際繪製的東西,而是這些內容的表明。因爲JavaScript對象是輕量級的,React能夠任意的建立和銷燬這些element對象,並且不用擔憂太大的消耗。另外,React能夠分析這些對象,把當前的對象和以前的對象對比,找出發生的改變,而後根據實際發生的改變來更新實際的DOM。react

爲了建立一個DOM節點的表明對象(也就是React element),咱們可使用React的createElement方法。spa

const element = React.createElement(
    'div',
    {id: 'login-btn'},
    'Login'
)

createElement方法傳入了三個參數。第一個是標籤名稱字符串(div、span等),第二個是給element設置的屬性,第三個是內容或者是子的React element。本例中的「Login」就是element的內容。上面的createElement方法調用後會返回一個這樣的對象:翻譯

{
    type: 'div’,
    props: {
        children: 'Login',
        id: 'login-btn'
    }
}

當這個對象繪製爲DOM(使用ReactDOM.render方法)的時候,咱們就會有一個新的DOM節點:code

<div id='login-btn'>Login</div>

有一個頗有意思的地方,咱們在學React的時候首先注意到的就是component(組件)。「Components(組件)是React的構建塊」。注意,咱們是以element開始本文的。並且你一旦理解了element,理解component也就是水到渠成的事了。一個component就是一個方法或者一個類,能夠接受必定的輸入,以後返回一個React element。component

function Button({onLogin}) {
    return React.createElement(
        'div',
        {id: 'login-btn', onClick: onLogin},
        'Login'
    )
}

在上面的定義中,咱們有一個Button組件(component)。接收一個onLogin輸入並返回一個React element。注意,Button組件接收的onLogin方法是它的prop。而後把這個方法經過createElement方法的第二個參數傳入到了實際的DOM裏。htm

更深刻一點

目前,咱們只接觸到了使用HTML元素來建立React element,好比「div」、「span」等。其實,你也能夠把其餘的React component(組件)做爲第一個參數傳入createElement方法。對象

const element = React.createElement(
    User,
    {name: 'Uncle Charlie'},
    null
)

然而,不一樣於通常的HTML標籤名稱,React若是發現第一個參數是class或者function類型的話,它就會檢查傳入的參數要繪製的是一個什麼element,傳入必要的props。以後React會一直檢查,直到沒有方法或者類做爲第一個參數傳入createElement。咱們來看看下面的例子:

function Button({addFriend}) {
    return React.createElement(
        'button',
        {onClick: addFriend},
        'Add Friend'
    )
}

function User({name, addFriend}) {
    return React.createElement(
        'div',
        null,
        React.createElement(
            'p',
            null,
            name
        ),
        React.createElement(Button, {addFriend})
    )
}

上面的例子裏有兩個component(組件)。一個Button,一個User。User「表明」了一個div,div裏面有兩個子節點:一個包含用戶名的「p」和一個Button組件。如今咱們看看上面的例子的具體的調用過程。

function Button({addFriend}) {
    return {
        type: 'button',
        props: {
            onClick: addFriend,
            children: 'Add Friend'
        }
    }
}

function User({name, addFreind}) {
    return {
        type: 'div',
        props: {
            children: [
                {
                    type: 'p',
                    props: {
                        children: name
                    }
                },
                {
                    type: Button,
                    props: {
                        addFriend
                    }
                }
            ]
        }
    }
}

在上面的代碼裏你會看到四種不一樣的屬性:「button」,「div」,「p」和Button。當React看到一個element是function和類類型的話,它就會檢查element會返回什麼element,並傳入對應的props。在這個過程結束以後,React就擁有了一個表明DOM樹的對象的數。上面的例子最後的結構是這樣的:

{
  type: 'div',
  props: {
    children: [
      {
        type: 'p',
        props: {
          children: 'Tyler McGinnis'
        }
      },
      {
        type: 'button',
        props: {
          onClick: addFriend,
          children: 'Add Friend'
        }
      }
    ]
  }
}

上面敘述的整個過程叫作Reconciliation(這個不知道怎麼翻譯,應該叫和諧?)。在React裏,每次調用setState方法或ReactDOM.render方法被調用的時候都會觸發這個過程。

那麼咱們來看看最開始的問題:

// 方法定義
function add(x, y) {
    return x + y
}

// 方法調用
add(1, 2)

// 組件定義
class Icon extends Component {}

// 組件調用??????
<Icon />

如今咱們已經有了回答這個問題的所有知識,除了一點點之外。有個地方,你可能以爲奇怪在使用React的時候,歷來沒有用過createElement方法來建立element。你是用了JSX。我(做者)最開始的時候說:「主要緣由是歷來沒有去詳細的瞭解過JSX和React實際操做之間的抽象層」。這個抽象層就是JSX會被Babel轉碼爲React.createElement方法的調用。

看看咱們前面的例子:

function Button({addFriend}) {
    return React.createElement(
        'button',
        {onClick: addFriend},
        'Add Friend'
    )
}

function User({ name, addFriend }) {
  return React.createElement(
    "div",
    null,
    React.createElement(
      "p",
      null,
      name
    ),
    React.createElement(Button, { addFriend })
  )
}

寫成JSX的樣子是這樣的:

function Button({addFriend}) {
    return (
        <button onClick={addFriend}>Add Friend</button>
    )
}

function User({name, addFriend}) {
    return (
        <div>
            <p>{name}</p>
            <Button addFriend={addFriend} />
        </div>
    )
}

因此,最後咱們應該怎麼回答前面的問題呢?<Icon />叫作什麼?

應該叫作「建立element」,應爲JSX最後會轉碼爲createElement方法的調用:

React.createElement(Icon, null)

前面的例子都是「建立一個React element」。

React.createElement(
  'div',
  { className: 'container' },
  'Hello!'
)

<div className='container'>Hello!</div>

<Hello />

原文地址:https://tylermcginnis.com/rea...

相關文章
相關標籤/搜索