React學(xué)習(xí)筆記(二)-- 理解JSX

摘要

JSX(JavaScriptXML)提供了一種在JavaScript中編寫聲明式的XML的方法乱顾,使用JSX可以提高組件的可讀性放闺,React允許做簡單的JSX語法轉(zhuǎn)化空郊。

簡介

JSX像是在JavaScript代碼里直接寫XML的語法谷饿,每一個(gè)XML標(biāo)簽都會(huì)被JSX轉(zhuǎn)換工具轉(zhuǎn)換成純JavaScript代碼未荒,React 官方推薦使用JSX荧降,這個(gè)看個(gè)人習(xí)慣接箫, 如果你喜歡純JavaScript代碼也是可以的,只是使用JSX會(huì)給我們帶來如下好處:

  • 是原生的JavaScript朵诫;
  • 程序結(jié)構(gòu)更容易被直觀化辛友;
  • 提供更加語義化且易懂的標(biāo)簽;
  • 抽象了React Element的創(chuàng)建過程剪返;
  • 允許使用熟悉的語法來定義HTML元素樹废累;
  • 可以隨時(shí)掌控HTML標(biāo)簽以及生成這些標(biāo)簽的代碼;

定義第一個(gè)組件

簡單的理解組件就是對數(shù)據(jù)和方法的簡單封裝脱盲,目的就是模塊化功能邑滨。在React當(dāng)中組件是用來分離關(guān)注點(diǎn)的,而不是被當(dāng)做模板或處理顯示邏輯的钱反,在使用React開發(fā)應(yīng)用過程中驼修,往往HTML標(biāo)簽以及生成這些標(biāo)簽的代碼之間存在著內(nèi)在的緊密聯(lián)系殿遂,其實(shí)這一坨代碼就可以理解為是一個(gè)組件。

接下來看一個(gè)簡單的DEMO乙各,定義我們的第一個(gè)組件墨礁,按照以往的游戲規(guī)則,我們就給他起一個(gè)文雅又響亮的名字——“HelloWorld”(React的安裝包可以到官網(wǎng)去下載):

<!DOCTYPE html>
<html> 
    <head> 
        <title>Hello React</title> 
        <!--React核心庫-->
        <script src="build/react.js"></script> 
        <!--react-dom.js提供與DOM相關(guān)功能-->
        <script src="build/react-dom.js"></script> 
        <!--browser.js將 JSX 語法轉(zhuǎn)為 JavaScript 語法-->
        <script src="build/browser.min.js">/script>
    </head> 
    <body> 
        <HelloWorld>Hello World!</HelloWorld>
        <!--為了把 JSX 轉(zhuǎn)成標(biāo)準(zhǔn)的 JavaScript耳峦,我們用 `<script type="text/babel">` 標(biāo)簽恩静,然后通過Babel轉(zhuǎn)換成在瀏覽器中真正執(zhí)行的內(nèi)容-->
        <script type="text/babel"> 
           // 定義組件HelloWorld
           var HelloWorld = React.createClass({
                render : function(){
                    return (
                        <div>
                            <h1>this.props.children</h1>
                        </div>
                    );
                }
            })
        </script> 
    </body>
</html>

關(guān)于上例中的幾點(diǎn)說明

  • React中組件名必須以大寫字母開頭;
  • React中的組件只能包含一個(gè)頂層標(biāo)簽蹲坷,否則會(huì)報(bào)錯(cuò)驶乾;
  • JSX將兩個(gè)花括號(hào)之間的內(nèi)容{...}渲染為動(dòng)態(tài)值,花括號(hào)指明了一個(gè)JavaScript上下文環(huán)境循签,它會(huì)將其中內(nèi)容進(jìn)行求值级乐,然后渲染為標(biāo)簽中的若干節(jié)點(diǎn);
  • this.props.children是組件的特殊屬性县匠,保存了開始標(biāo)簽與結(jié)束標(biāo)簽之間的所有子節(jié)點(diǎn)风科,上例中this.props.children = ["Hello World!"];

上述代碼如果不使用JSX語法乞旦,寫法如下:

...
// 定義組件HelloWorld
var HelloWorld = React.createClass({displayName:"HelloWorld ",
    render : function(){
        return (
             React.createElement("div",null);
             React.createElement("h2",null,this.props.children);
           );
    }
})
...

不管使不使用JSX贼穆,HelloWorld組件最終的頁面渲染結(jié)果都是一樣的,如下所示:

<div>
    <h1>Hello World!</h1>
</div>

JSX與HTML有何不同

“這個(gè)規(guī)范(JSX)并不嘗試去遵循任何XML或HTML規(guī)范兰粉。JSX是作為一種ECMAScript特性來設(shè)計(jì)的故痊,至于大家覺得JSX像XML這一事實(shí),那僅僅是因?yàn)榇蠹冶容^熟悉XML玖姑°碉”——以上內(nèi)容摘自http://facebook.github.io/jsx/

由此我們可以看出JSX僅僅是像HTML而已,接下來看下他們之間的關(guān)鍵區(qū)別焰络。

屬性

在HTML中我們往往通過內(nèi)聯(lián)的方式設(shè)置標(biāo)簽的屬性戴甩,JSX在支持這種方式的基礎(chǔ)上,還支持動(dòng)態(tài)的設(shè)置標(biāo)簽的屬性舔琅,具體實(shí)現(xiàn)形式如同我們上個(gè)DEMO中的{...}等恐,我們可以將屬性值定義為JS變量或者是函數(shù)。如下所示:

<!--在HTML中標(biāo)簽屬性示例-->
<div id="demo" class="myStyle"></div>

<!--在JSX中標(biāo)簽屬性示例-->
var demoId = this.props.id;
var demoClass = "myStyle";
function getName(){
    ...
}
<div id={demoId} name={this.getName()} className={demoClass}></div>

在React渲染組件的過程中备蚓,我們上面定義的變量和函數(shù)會(huì)被求值课蔬,最終生成的DOM結(jié)構(gòu)會(huì)反映出這個(gè)新的狀態(tài)。

非DOM屬性

下列屬性只在JSX中存在:

  • key:可選的唯一標(biāo)示符郊尝,用來唯一的標(biāo)識(shí)一個(gè)組件二跋;
  • ref :允許父組件在render之外保持對子組件的一個(gè)引用;
  • dangerouslySetInnerHtml:提供插入純 HTML 字符串的功能流昏,主要為了能和生成 DOM 字符串的庫整合扎即。

接下來詳細(xì)看一下這幾個(gè)特殊屬性的作用吞获。

鍵(key)
在程序運(yùn)行過程中,由于用戶與應(yīng)用間的交互等原因谚鄙,一個(gè)組件在組件樹中的位置很有可能發(fā)生改變各拷,最常見的例子就是某列表記錄的增、刪操作闷营。當(dāng)然這種情形下組件可能并不需要被銷毀并重新創(chuàng)建烤黍。

通過給組件設(shè)置一個(gè)唯一的標(biāo)識(shí),且保證它在一個(gè)渲染周期中保持一致傻盟,這樣React就能智能的決定該重用哪一個(gè)組件速蕊,或者銷毀并重新創(chuàng)建一個(gè)組件,避免不必要的重新渲染娘赴,得到性能的提升规哲。

引用(ref)
在JSX中可以通過在屬性中設(shè)置期望的引用名來定義一個(gè)引用。

var App = React.createClass({ 
    getInitialState: function() { 
        return {userInput: ''}; 
    }, 
    handleChange: function(e) { 
        this.setState({userInput: e.target.value}); 
    }, 
    clearAndFocusInput: function() { 
        // 清空輸入框
        this.setState({userInput: ''}, 
        function() { 
            // 這段代碼會(huì)在組件重新渲染后執(zhí)行诽表,使輸入框重獲焦點(diǎn)
            this.refs.theInput.getDOMNode().focus(); 
        }); 
    }, 
    render: function() { 
    return ( 
        <div> 
           <div onClick={this.clearAndFocusInput}> 
               點(diǎn)我唉锌!點(diǎn)我!关顷!點(diǎn)我:选N涓!议双!
          </div> 
          <input ref="theInput" value={this.state.userInput} onChange={this.handleChange} /> 
        </div> 
        ); 
     } 
});

然后我們就可以在組件中的任何地方使用這個(gè)引用了。通過引用獲取到的這個(gè)對象叫做支持實(shí)例捉片。他并不是一個(gè)真的DOM平痰,而是React在需要時(shí)創(chuàng)建的一個(gè)描述對象。你可以通過this.refs.theInput.getDomNode()來訪問真實(shí)的DOM節(jié)點(diǎn)伍纫。

設(shè)置原始的HTML
dangerouslySetInnerHTML—— 顧名思義宗雇,從屬性名當(dāng)中就能看出來,以此來警告它的值( 一個(gè)對象而不是字符串 )應(yīng)該被用來表明凈化后的數(shù)據(jù)莹规。在徹底的理解安全問題后果并正確地凈化數(shù)據(jù)之后赔蒲,生成只包含唯一 key __html 的對象,并且對象的值是凈化后的數(shù)據(jù)良漱,示例如下:

function createMarkup() { 
     return {__html: 'First · Second'};
 };
<div dangerouslySetInnerHTML={createMarkup()} />

這么做的意義在于舞虱,當(dāng)你不是有意地使用 <div dangerouslySetInnerHTML={getUsername()} />時(shí)候,它并不會(huì)被渲染母市,因?yàn)?getUsername() 返回的格式是 字符串 而不是一個(gè){__html: ''} 對象矾兜。{__html:...} 背后的目的是表明它會(huì)被當(dāng)成 "type/taint" 類型處理。 這種包裹對象患久,可以通過方法調(diào)用返回凈化后的數(shù)據(jù)椅寺,隨后這種標(biāo)記過的數(shù)據(jù)可以被傳遞給dangerouslySetInnerHTML浑槽。 基于這種原因,我們不推薦寫這種形式的代碼:<div dangerouslySetInnerHTML={{__html: getMarkup()}} />

這個(gè)功能主要被用來與 DOM 字符串操作類庫一起使用返帕,所以提供的 HTML 必須要格式清晰(例如:傳遞 XML 校驗(yàn) )

注釋

由于JSX本質(zhì)上就是JavaScript桐玻,因此也支持JavaScript的注釋方式,在JSX中可以用以下兩種方式添加注釋:

  • 當(dāng)做一個(gè)元素的子節(jié)點(diǎn)荆萤;
  • 內(nèi)聯(lián)在元素的屬性中畸冲;

示例如下:

// 作為一個(gè)元素的子節(jié)點(diǎn)
<div>
{/*多行注釋*/}
<h1>This is a h1 tag.</h1>
</div>

// 內(nèi)聯(lián)在元素的屬性中
<div>
<h1
/*
 * 多行注釋
 */ 
> 多行注釋  </h1>
</div>

<div>
<h1
//單行注釋 
>單行注釋</h1>
</div>

特殊屬性

由于JSX會(huì)轉(zhuǎn)化為JavaScript函數(shù),所以有些關(guān)鍵詞我們不可以使用观腊,比如forclass邑闲。

這兩個(gè)屬性分別可以用htmlForclassName替換,參考如下示例:

<label htmlFor="name" ...>
<input calssName={classes} ...>

樣式

React把所有的內(nèi)聯(lián)樣式都規(guī)范化為駝峰形式梧油,同樣類似于JavaScript中DOM的style屬性苫耸,要給組件添加自定義屬性,如下:

var styles = {
    width:100px;
    height:100px;
}

React.renderComponent({<div style={styles}>...</div>,node})

參考

【1】《React引領(lǐng)未來的用戶界面開發(fā)框架》
【2】 React中文官網(wǎng)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末儡陨,一起剝皮案震驚了整個(gè)濱河市褪子,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌骗村,老刑警劉巖嫌褪,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異胚股,居然都是意外死亡笼痛,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進(jìn)店門琅拌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缨伊,“玉大人,你說我怎么就攤上這事进宝】谭唬” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵党晋,是天一觀的道長谭胚。 經(jīng)常有香客問我,道長未玻,這世上最難降的妖魔是什么灾而? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮深胳,結(jié)果婚禮上绰疤,老公的妹妹穿的比我還像新娘。我一直安慰自己舞终,他們只是感情好轻庆,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布癣猾。 她就那樣靜靜地躺著,像睡著了一般余爆。 火紅的嫁衣襯著肌膚如雪纷宇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天蛾方,我揣著相機(jī)與錄音像捶,去河邊找鬼抚吠。 笑死沉眶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的钦听。 我是一名探鬼主播亚隅,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼硼莽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了煮纵?” 一聲冷哼從身側(cè)響起懂鸵,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎行疏,沒想到半個(gè)月后匆光,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酿联,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年终息,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片货葬。...
    茶點(diǎn)故事閱讀 40,498評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡采幌,死狀恐怖劲够,靈堂內(nèi)的尸體忽然破棺而出震桶,到底是詐尸還是另有隱情,我是刑警寧澤征绎,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布蹲姐,位于F島的核電站,受9級(jí)特大地震影響人柿,放射性物質(zhì)發(fā)生泄漏柴墩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一凫岖、第九天 我趴在偏房一處隱蔽的房頂上張望江咳。 院中可真熱鬧,春花似錦哥放、人聲如沸歼指。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽踩身。三九已至胀茵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挟阻,已是汗流浹背琼娘。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留附鸽,地道東北人脱拼。 一個(gè)月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像坷备,于是被迫代替她去往敵國和親挪拟。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容