React中元素與組件的區別

在初學 React 的時候,分不清 React 組件和 React 元素,着實踩了一些坑。搞清楚 React 中什麼是組件,什麼是元素,既能夠理清楚概念,也可讓你避免一些沒必要要的錯誤。數組

React 元素

React 元素(React element),它是 React 中最小基本單位,咱們可使用 JSX 語法輕鬆地建立一個 React 元素:數據結構

const element = <div className="element">I'm element</div>

React 元素不是真實的 DOM 元素,它僅僅是 js 的普通對象(plain objects),因此也沒辦法直接調用 DOM 原生的 API。上面的 JSX 轉譯後的對象大概是這樣的:函數

{
    _context: Object,
    _owner: null,
    key: null,
    props: {
    className: 'element',
    children: 'I'm element'
  },
    ref: null,
    type: "div"
}

只有在這個元素渲染被完成後,才能經過選擇器的方式獲取它對應的 DOM 元素。不過,按照 React 有限狀態機的設計思想,應該使用狀態和屬性來表述組件,要儘可能避免 DOM 操做,即使要進行 DOM 操做,也應該使用 React 提供的接口refgetDOMNode()。通常使用 React 提供的接口就足以應付須要 DOM 操做的場景了,所以像 jQuery 強大的選擇器在 React 中幾乎沒有用武之地了。 this

除了使用 JSX 語法,咱們還可使用 React.createElement()React.cloneElement() 來構建 React 元素。spa

React.createElement()

JSX 語法就是用React.createElement()來構建 React 元素的。它接受三個參數,第一個參數能夠是一個標籤名。如divspan,或者 React 組件。第二個參數爲傳入的屬性。第三個以及以後的參數,皆做爲組件的子組件。設計

React.createElement(
    type,
    [props],
    [...children]
)

React.cloneElement()

React.cloneElement()React.createElement()類似,不一樣的是它傳入的第一個參數是一個 React 元素,而不是標籤名或組件。新添加的屬性會併入原有的屬性,傳入到返回的新元素中,而就的子元素獎盃替換。code

React.cloneElement(
  element,
  [props],
  [...children]
)

React 組件

React 中有三種構建組件的方式。React.createClass()ES6 class和無狀態函數。對象

React.createClass()

React.createClass()是三種方式中最先,兼容性最好的方法。在0.14版本前官方指定的組件寫法。blog

var Greeting = React.createClass({
  render: function() {
    return <h1>Hello, {this.props.name}</h1>;
  }
});

ES6 class

ES6 class是目前官方推薦的使用方式,它使用了ES6標準語法來構建,但它的實現還是調用React.createClass()來實現了,ES6 class的生命週期和自動綁定方式與React.createClass()略有不一樣。接口

class Greeting extemds React.Component{
  render: function() {
    return <h1>Hello, {this.props.name}</h1>;
  }
};

無狀態函數

無狀態函數是使用函數構建的無狀態組件,無狀態組件傳入propscontext兩個參數,它沒有state,除了render(),沒有其它生命週期方法。

function Greeting (props) {
  return <h1>Hello, {props.name}</h1>;
}

React.createClass()ES6 class構建的組件的數據結構是類,無狀態組件數據結構是函數,它們在 React 被視爲是同樣的。

元素與組件的區別

組件是由元素構成的。元素數據結構是普通對象,而組件數據結構是類或純函數。除此以外,還有幾點區別要注意:

this.props.children

在 JSX 中,被元素嵌套的元素會以屬性 children 的方式傳入該元素的組件。當僅嵌套一個元素時,children 是一個 React 元素,當嵌套多個元素時,children 是一個 React 元素的數組。能夠直接把 children 寫入 JSX 的中,但若是要給它們傳入新屬性,就要用到React.cloneElement()來構建新的元素。我曾放過如下錯誤:

render () {
  var Child = this.props.children
  return <div><Child tip={'error!'}/><div>
}

由於 Child 是一個 React 元素,而不是組件,這樣的寫法是徹底錯誤的,正確的方式應該是:

render () {
  var child = this.props.children
  return <div>{ React.cloneElement(child, {tip: 'right way!'}) }<div>
}

就這樣,原有屬性和新添加的屬性被一併傳入了子元素。使用React.cloneElement()纔是操做元素的正確姿式。

用戶組件

有的時候,組件可讓用戶以屬性的方式傳入自定義的組件,來提高組件的靈活性。這個屬性傳入的就應該是 React 元素,而非 React 組件。使用 React 元素可讓用戶傳入自定義組件的同時,爲組件添加屬性。一樣,可使用React.cloneElement()爲自定義組件添加更多屬性,或替換子元素。

// 推薦
<MyComponent tick={
  <UserComponent tip="Yes"/>
} />

// 不推薦
<MyComponent tick={ UserComponent } />

最後

最後,打個不恰當的比喻,React 組件是MyComponent,React 元素就是<MyComponent />

AD

新開博客,更多文章,陸續更新中...

相關文章
相關標籤/搜索