本篇爲譯文,原文出處:React Elements vs React Components vs Component Backing Instancesjavascript
許多人可能據說過 Facebook 的 React 庫,並在本身的工做或項目中使用它。React 是很是流行的,使開發用戶界面變得簡單且符合聲明式編程(譯者注:聲明式編程能夠參考聲明式編程和命令式編程的比較)。html
正如題目所示,React 有幾個概念遍佈其文檔,這(幾個概念)可能會讓新React用戶困惑。例如,你在 Glossary、Top-Level API 和 Explanation on Refs 這幾章中檢索 「React Element」、「React Component」 和 「Component Backing Instance」,你會發現這幾個術語遍佈各處,已是 React 的絕對的核心。java
這篇文章不是一篇 React 的教程,更多的是分享我最近學習 React 而獲得的一些(知識)。所以,這篇文章是針對以前已經涉獵過 React 的人們,我會假設你已經熟悉 React 一些核心概念和語法。react
React 元素這個概念對於 React 來講很重要,可是我堅信一點,由於使用 React 和 JSX 來構建用戶界面過於簡單,從而致使可能在最初錯過這個概念。若是你以前用過 React + JSX,毫無疑問的說,在你的 JS 文件中書寫類 HTML 語法更加符合你的習慣(譯者注:Habit is second nature. 習慣成天然)。在這種(書寫類HTML語法)假象之下,JSX 語法實際上被編譯成特殊的函數調用 — React.createElement()
。 猜猜 React.createElement()
會產生什麼?耶,你猜對了,就是 React 元素。讓咱們看一個轉換過程的例子:git
// 使用 JSX 語法 var helloWorld = <div>Hello World!</div>; // 而後是 JSX 被編譯成 JavaScript 後的結果 var helloWorld = React.createElement( "div", null, "Hello World!" ); // 再是處理成 JavaScript 簡單對象後看起來相似這樣 var helloWorld = { key: null, props: { children: "Hello World!" // more stuff in here }, ref: null, type: "div" // more stuff in here };
React 元素是由一些屬性(properties)構成的 JavaScript 簡單對象(plain old JavaScript objects,譯者注:關於更多解釋能夠看 Plain Old JavaScript,What is a plainObject in JavaScript?):es6
key - 屬性 key 是用來在一組相同類型的 React 元素構成的 Array 中標識惟一特定 React 元素。你沒必要提供一個值給它(譯者注:在新版 React 中,若是在循環一組相同類型的 React 元素時不指定 key,會報一個 warning 錯誤,具體能夠參考 React 對循環 warning 提示增長 key 的研究),可是若是你給 key 提供一個值,React 將可以進行優化,使從新渲染過程更高效。github
props - 屬性props 偏偏是你所認爲的: 它是向下傳遞給子組件(child components)的全部 props 和 values 的映射(集合)。算法
ref - 屬性ref 用來訪問與這個 React 元素相關聯的通過(瀏覽器或渲染引擎)渲染處理後的底層 DOM 元素。編程
type - 屬性type 將是兩種格式之一,表示任何有效的 HTML 元素的(名稱)字符串 或 指向 React 組件類的引用。segmentfault
此時, 瞭解每一個屬性全部細節並不重要。最大的收穫在於,React 元素僅僅是 JavaScript 簡單對象(plain old JavaScript objects),用來描述組件的 HTML 應是怎樣的結構,這個對象上不包含任何方法(Methods),僅僅只有數據。
經過以前 helloWorld
React 元素的例子告訴你,helloWorld
表示一個子節點爲「Hello World!」文本的 div 標籤。即便你建立了一個更復雜的 JSX 例子,生成的 React 元素仍將是一個 JavaScript 對象,配合其餘嵌套 React 元素描述 HTML 將是怎樣的結構。若是這讓你感受熟悉,是由於這正是虛擬 DOM(Virtual DOM)是什麼(的解釋) - 它是 DOM 在特定時間段應該是怎樣的結構的描述,經過 React 元素聲明來表示。
不一樣於 React 元素,你可能對 React 組件更熟悉一些。若是你曾寫過相似下面例子的代碼,那麼你以前已經建立過 React 組件類了:
// 這是一個 React 組件類 class CustomForm extends React.Component { constructor(props) { super(props); this.state = { inputText: "Willson" }; this.handleInputChange = this.handleInputChange.bind(this); } handleInputChange(e) { const inputText = e.target.value; this.setState({ inputText }); } render() { return ( <div className="custom-form"> <div className="custom-form-header"> <p>Hello, {this.state.inputText}</p> </div> <div className="custom-form-body"> <input type="text" value={this.state.inputText} onChange={this.handleInputChange} /> </div> </div> ); } } /* * 我假設你有可用的 React 和 ReactDom,以及 * 一個 id 爲 "root" 的 HTML 元素 * ReactDOM.render() 的返回值是組件實例 */ var componentInstance = ReactDOM.render(<CustomForm />, document.getElementById("root"));
上面的例子是用 ES2015 新的 Class 語法寫的,但它幾乎至關於使用 React.createClass()
。你也許熟悉編寫這些組件類,但重要的是(React文檔中所述的)React 組件指代的是一個 React 組件類的實例。
假如你熟悉 JavaScript 的話,當你聽到到「實例化一個類」且智商在線時,你可能會考慮使用new
操做符。然而,(在 React 中)從不須要你用 new
操做符建立 React 組件。相反的是,你將使用 ReactDOM.render()
把一個 React 元素渲染成一個特定的 DOM 元素,與此同時,ReactDOM.render()
將返回一個 React 組件實例。
從 ReactDOM.render()
返回的組件實例能夠調用在 React 組件類中定義的方法。反過來想一下會讓你明白,ReactDOM.render()
是 React 爲你實例化一個組件的機制。一般, 你不須要訪問組件實例自己, 但我發如今測試 React 組件時, 將組件實例的引用保存下來(對測試)頗有幫助。
與 ReactDOM.render()
有關的最後一個有趣的點是,React 在 ReactDOM.render()
時對虛擬 DOM 執行高效的 diff 算法(譯者注: diff 算法延伸閱讀)。若是你記得(上面說的),React 元素表示虛擬 DOM(元素),這意味着 ReactDOM.render()
接收一個虛擬 DOM(元素),將其渲染成一個真實 DOM 元素,返回(React 元素 type 指定的)組件實例。在底層,若是你將相同的React元素類型(帶有可能不一樣的 props 值)經過 ReactDOM.render()
渲染成相同的 DOM 元素,React 將執行 diff 算法,對 DOM 元素進行僅必須的最小更改。也許使人驚訝的是,它每次返回相同的組件實例 - 除了更新的 prop 和 state 值。
前兩節探討了 React 元素和 React 組件實例,這兩個概念都是 DOM 之上的抽象層。 如今咱們將討論術語「組件支撐實例」,以及它們自身如何與真實 DOM 元素相關聯。
// 組件類 class CustomForm extends React.Component { constructor(props) { super(props); this.state = { inputText: "Willson" }; this.handleInputChange = this.handleInputChange.bind(this); } handleInputChange(e) { const inputText = e.target.value; this.setState({ inputText }); } render() { return ( <div className="custom-form"> <div className="custom-form-header"> <p>Hello, {this.state.inputText}</p> </div> <div className="custom-form-body"> <input type="text" value={this.state.inputText} onChange={this.handleInputChange} /> </div> </div> ); } } // 組件實例 var componentInstance = ReactDOM.render(<CustomForm />, document.getElementById("root")); // DOM 實例 var domInstance = ReactDOM.findDOMNode(componentInstance); // 原文做者這裏出了個 Bug,多了一個 D
在前面的實例中,ReactDOM.render()
經過將 React 元素渲染到現有的 DOM 元素中來生成一個組件實例。正如咱們已經知道的,組件實例不是真實 DOM 節點。然而,訪問與組件實例關聯的底層 DOM 節點實際上很簡單 - 咱們使用 ReactDOM.findDOMNode()
,並將組件實例做爲其參數傳遞。那麼這與「組件支撐實例」術語有什麼關係呢?讓咱們一臉懵逼的是,React 在其文檔的各處將引用的真實 DOM 節點稱之爲組件支撐實例。
這3個術語「React 元素」,「React 組件」和「組件支撐實例」是密切相關的。 因爲 JSX 語法被轉譯爲 React.createElement()
調用(譯者注:理解轉譯這個概念能夠參考 Compiling Vs Transpiling),最終返回咱們稱之爲「React 元素」的 JavaScript 簡單對象(plain old JavaScript objects),你能夠將 React元素視爲基礎構建單元。React 組件實例表示下一個抽象層 - ReactDOM.render()
接收一個 React 元素、引用一個真實 DOM 節點、返回一個 React 組件實例。該實例能夠訪問組件類中定義的方法,可是在單元測試以外不多用到這一點。React 元素和 React 組件實例都不表示真實 DOM 元素。渲染組件實例產生的 DOM 元素被稱爲組件支撐實例,訪問它的主要方式是使用ReactDOM.findDOMNode()
。
我但願這篇文章可以幫助你理清這些術語!
[參考資料]
Backing Instances 翻譯成 支撐實例 來自於 理解React中es6方法建立組件的this