此文檔只是針對本身在學習react的過程當中進行的翻譯。可能不是太專業,可是基於本身的理解,用於日後的查閱來講應該是足夠了。javascript
思考如下變量的聲明: const element = <h1>Hello, world!<h1> 以上有意思的語法,既不是字符串,也不是HTML。 咱們稱之爲JSX,它是基於JavaScript的擴展語法。咱們推薦在React中使用JSX語法來描述UI應該是什麼樣子的。JSX也許會讓你想到模板 語言,可是它可以很好的與JavaScript結合,具備JavaScript一樣強大的功能。 JSX用於生成React的元素(elements),咱們將在下一章節探討如何把它們渲染到DOM上。接下來, 你將會了解到開始使用JSX須要掌握的 一些必要知識。
在JSX中能夠嵌入任何JavaScript 表達式,經過使用一對花括號「{}」進行包裹。 例如2 + 2, user.firstName, 和 formatName(user)都是有效的表達式:
import React from 'react'; import ReactDom from 'react-dom'; function formatName(user) { return user.firstName + ' ' + user.lastName; } const user = { firstName: 'Harper', lastName: 'Perez' }; const element = ( <h1> Hello, {formatName(user)}! </h1> ); ReactDom.render( element, document.getElementById('root') );
輸出結果爲: Hello, Harper Perez! 爲了方便閱讀,咱們把JSX分割成多行來書寫,固然並非必須的,可是若是要這麼作的話,咱們仍是建議用圓括號括起來,從而避免分號自動 插入的陷阱。
編譯以後,JSX表達式就會變成普通的JavaScript對象。 這意味着你能夠在if以及for語句塊裏使用JSX,賦值給一個變量,當作參數傳遞以及做爲函數的返回值:
function getGreeting(user) { if (user) { return <h1>Hello, {formatName(user)}!</h1>; } return <h1>Hello, Stranger.</h1>; }
你可使用引號來爲屬性指定字符串常量值:
const element = <div tabIndex="0"></div>;
你也能夠在屬性值中使用花括號來嵌套JavaScript表達式:
const element = <img src={user.avatarUrl}></img>;
當使用花括號來嵌套JavaScript表達式的時候,不要在花括號外面使用引號來嵌套。不然JSX將會把該值當作一個字符串字面量來處理,而不是 表達式。在同一個屬性值當中,你可使用花括號和引號中的任意一個,可是不能兩個都同時使用。
若是一個標籤是空的,你可使用‘/>’進行標籤的閉合。看以下的XML:
const element = <img src={user.avatarUrl} />;
JSX標籤可能會包含子元素:
const element = ( <div> <h1>Hello!</h1> <h2>Good to see you here.</h2> </div> );
警告:比起HTML,JSX更接近於JavaScript,因此JSX採用駝峯式的屬性命名約定來代替HTML中的屬性名。 例如在JSX中,class變爲className, tabindx變爲tabIndex。
在JSX中嵌入用戶的輸入是安全的:
const title = response.potentiallyMaliciousInput; // This is safe: const element = <h1>{title}</h1>;
默認狀況下, 在渲染以前,React Dom會把嵌套在JSX裏的任何值進行轉義,也就是意味着,你沒法注入任何非明確在應用中指定的東西。 在渲染以前,全部的值都會被轉換成字符串,這幫助解決了跨站點攻擊。
Babel 把 JSX 語法編譯以後,其實就是調用了 React.createElement(). 如下的兩個實例是等效的:
const element = ( <h1 className="greeting"> Hello, world! </h1> ); const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' ); React.createElement() 在執行的時候進行了一些校驗以幫助咱們寫出更加健壯的代碼,本質上它建立了以下的一個對象: // 注意: 當前這個結構是簡化了的 const element = { type: 'h1', props: { className: 'greeting', children: 'Hello, world' } };
這樣的對象咱們稱之爲React元素。你能夠把它想象爲咱們在屏幕上所看到元素的一個描述。React讀取這些對象,使用它們來構造DOM,而且保持實時更新。 咱們將在下一章節討論如何把React的元素渲染到DOM上。 提示: 咱們推薦使用支持Babel的編輯器,從而es6和JSX語法均可以正確的高亮顯示。
元素是React應用中最小的構建模塊。 一個元素描述了你想要在屏幕上看到的東西:
const element = <h1>Hello, world<h1/>;
不像瀏覽器DOM元素那樣,React元素是簡單的對象,而且易於建立。(瀏覽器的元素建立代價比較昂貴)React DOM 兼顧更新DOM去匹配React元素。 注意: 另一個被你們熟知的概念「組件」可能會使元素理解起來比較困惑。咱們將在下一章節講解組件。元素是組件 的組成部分, 咱們建議在閱讀下一章節前仔細閱讀該部分的內容。
假設在你的HTML文件中有一個<div>元素: <div id="root"></div> 咱們稱之爲根元素節點,由於在該元素當中的全部內容將會由React DOM 所管理。 使用React構建的應用一般來講只有單一的一個根節點。若是你想在現有的應用中集成React的話,那你能夠定義多個 孤立的根節點。 渲染React元素到根DOM節點上,把兩者都傳遞給ReactDom.render():
const element = <h1>Hello, world</h1>; ReactDOM.render( element, document.getElementById('root') );
在頁面中將會顯示: Hello, world
React元素是不可變的。只要建立一個元素以後,就不能改變它的子元素和屬性。一個元素就像是電影中的某一幀:它 表明了在某一個肯定的時間點上的UI展示。 根據咱們目前的知識,更新UI的惟一途徑是建立一個新的元素,傳遞給ReactDOM.render()進行渲染。 思考如下時鐘的示例:
function tick() { var element = ( <div> <h1>Hello, world!</h1> <h2>It is {new Date().toLocaleTimeString()}.</h2> </div> ); ReactDom.render( element, document.getElementById('root') ); } setInterval(tick, 1000);
每隔一秒鐘setInteval的回調就會去調用一次ReactDom.render()。 注意: 在實踐中,大多數的React應用只調用一次ReactDom.render()。下一個章節中,咱們將會學習如何在 有狀態的組件(stateful components)中去封裝這樣的代碼。
React DOM會比較前一個元素以及它的子元素,而且只會去更新須要更新的DOM,從而達到預期的效果。 你能夠運行上一個例子,經過瀏覽器工具來進行驗證。(如下爲實例的截圖)
儘管咱們在每一秒鐘的時候建立了一個描述整個UI樹的元素,可是隻有文本節點當中的內容被React DOM更新了。
組件可讓你把UI分紅獨立的,可服用的一些代碼塊。每個代碼塊均可以單獨的考慮。 在概念上,組件相似於JavaScript的函數(function)。他們接收任意的輸入(稱之爲「props」),返回一個React 元素, 描述了屏幕上應該顯示的信息。
定義組件的最簡單的方式是寫一個JavaScript函數:
function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
這個函數是一個有效的React組件,由於它接收一個單一的props對象做爲參數,而且返回了一個React元素。咱們稱之爲 函數化的組件,由於從字面上來看它就是一個JavaScript函數。 你一樣可使用es6的class來定義一個組件:
class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }
從React的角度來看,以上兩個組件是等價的。 Classes 有一些其餘的特性,咱們將在下一章節探討。鑑於函數化的組件簡潔,咱們將使用它來進行組件的定義。
在上面的示例中,咱們僅僅使用到了表示DOM標籤的React元素:
const element = <div />;
另外,元素也能夠是用戶自定義的組件:
const element = <Welcome name="Sara" />;
當React遇到用戶自定義的組件的時候,它把JSX屬性當作一個對象傳遞給組件,咱們把改對象稱之爲「props」。 例如,下面的代碼將會把「Hello, Sara」渲染到上:
function Welcome(props) { return <h1>Hello, {props.name}</h1>; } const element = <Welcome name="Sara" />; ReactDOM.render( element, document.getElementById('root') );
讓咱們回顧下這個示例都發生了什麼: 1. 咱們調用ReactDom.render()來渲染<Welcome name="Sara" /> 2. React調用Welcome組件,把{name: 'Sara'}做爲props 3. Welcome組件返回一個<h1>Hello, Sara</h1>元素做爲結果。 4. React DOM會及時的更新DOM去匹配 <h1>Hello, Sara</h1> 警告: 組件名稱要以大寫字母開頭。 例如:<div />表示DOM標籤,可是<Welcome />表明一個組件。
組件能夠被另一個組件所引用。這使得咱們能夠在不一樣層級的詳細信息中使用同一個組件。一個button,form, dialog,screen:在React中,這些一般都表現爲一個組件。 例如,咱們能夠建立一個屢次渲染 Welcome 的組件App:
function Welcome(props) { return <h1>Hello, {props.name}</h1>; } function App() { return ( <div> <Welcome name="Sara" /> <Welcome name="Cahal" /> <Welcome name="Edite" /> </div> ); } ReactDOM.render( <App />, document.getElementById('root') );
典型的,新的React應用會在頂部有一個單一的App組件。然而,若是是在已有的項目中集成React,你能夠經過自下而上的方式,從一個小的組件例如Botton開始,按照你本身的方式逐漸的由下而上 到達視圖的頂部。 警告: 組件必須返回一個單一根元素的元素。這就是爲何咱們添加一個<div>來包含全部的<Welcome /> 元素了。
不要擔憂把組件切分爲更小的組件。 例如,思考以下的 Comment 組件:
function Comment(props) { return ( <div className="Comment"> <div className="UserInfo"> <img className="Avatar" src={props.author.avatarUrl} alt={props.author.name} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); }
它接收author(一個對象),text(字符串),以及date(日期)做爲props,描述了一個社交媒體 網站上的評論。 由於嵌套的關係,這個評論組件很差去作改動,也難於重用其中的我的信息部分。讓咱們從中提取 一些組件。 首先,咱們將提取Avatar:
function Avatar(props) { return ( <img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} /> ); }
Avatar組件並不須要知道在Comment組件當中被渲染了。這也是爲何咱們把prop的name定義爲 更加通用的user,而不是author。 咱們更加推薦從組件自身的視圖角度來命名props,而不是經過他被使用的場景來定義。 如今咱們能夠稍微的簡化下Comment:
function Comment(props) { return ( <div className="Comment"> <div className="UserInfo"> <Avatar user={props.author} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); }
下一步咱們將要提取UserInfo組件,該組件緊挨着用戶的姓名,渲染一個Avatar組件:
function UserInfo(props) { return ( <div className="UserInfo"> <Avatar user={props.user} /> <div className="UserInfo-name"> {props.user.name} </div> </div> ); }
這讓咱們進一步的簡化Comment組件:
function Comment(props) { return ( <div className="Comment"> <UserInfo user={props.author} /> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); }
提取組件彷佛是一件枯燥乏味的工做,可是在大型的應用中提供了可重用組件的模板。首要的一個原則 就是若是UI中的一部分被使用了屢次(Button, Panel, Avatar),或者足夠的複雜(pp, FeedStory,Comment),它將會是可重用組件的最佳候選。
無論你是經過function或者是class的方式申明的組件,它從不會修改它自身的props。思考以下的 Sum函數:
function sum(a,b) { renturn a + b; }
相似這樣的函數咱們稱之爲純粹(pure)的函數,由於這樣的函數不會試圖去改變他們的輸入參數, 而且相同的輸入老是返回相同的結果。 相反,以下的函數並非純粹的,由於它改變了它的入參。
function withdraw(account, amount) { account.total -= amount; }
React很是的靈活,可是它有一條很是嚴格的規則: 全部的React組件必須像純粹的函數同樣,不去影響到他們的props。 固然,應用程序的UI是隨時在變化的。在下一個章節,咱們將介紹一個新的概念:state。State容許 React組件根據用戶的動做、網絡的響應以及其餘的事件來改變他們的輸出,可是並不違背這一原則。 待續...