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è)組件

簡單的理解組件就是對(duì)數(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之外保持對(duì)子組件的一個(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)我!?。?          </div> 
          <input ref="theInput" value={this.state.userInput} onChange={this.handleChange} /> 
        </div> 
        ); 
     } 
});

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

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

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

這么做的意義在于,當(dāng)你不是有意地使用 <div dangerouslySetInnerHTML={getUsername()} />時(shí)候,它并不會(huì)被渲染,因?yàn)?getUsername() 返回的格式是 字符串 而不是一個(gè){__html: ''} 對(duì)象。{__html:...} 背后的目的是表明它會(huì)被當(dāng)成 "type/taint" 類型處理。 這種包裹對(duì)象,可以通過方法調(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)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 以下內(nèi)容是我在學(xué)習(xí)和研究React時(shí),對(duì)React的特性、重點(diǎn)和注意事項(xiàng)的提取、精練和總結(jié),可以做為React特性...
    科研者閱讀 8,396評(píng)論 2 21
  • 本筆記基于React官方文檔,當(dāng)前React版本號(hào)為15.4.0。 1. 安裝 1.1 嘗試 開始之前可以先去co...
    Awey閱讀 7,913評(píng)論 14 128
  • 原教程內(nèi)容詳見精益 React 學(xué)習(xí)指南,這只是我在學(xué)習(xí)過程中的一些閱讀筆記,個(gè)人覺得該教程講解深入淺出,比目前大...
    leonaxiong閱讀 2,931評(píng)論 1 18
  • 原文地址:Learning React.js is easier than you think原文作者:Samer...
    sunshine小小倩閱讀 4,328評(píng)論 3 41
  • 請(qǐng)老師指正
    Na滋味閱讀 207評(píng)論 0 0

友情鏈接更多精彩內(nèi)容