學習React從接受JSX開始

來源:互聯網
上載者:User

詳情參考官方JSX規範

雖然JSX是擴充到ECMAScript的類XML文法,但是它本身並沒有定義任何語義。也就是說它本身不在ECMAScript標準範圍之內。它也不會被引擎或者瀏覽器直接執行。通常會利用很編譯器前置處理器來將這些JSX轉化為標準的ECMAScript。

吐槽:雖然JSX出發點是好的,而且寫起來也很簡單,但是對於要在JS中寫類HTML格式的內容,我的內心是排斥的,感覺非常不習慣。這不是我熟知的web開發啊!有種在開發app的感覺,一個個自訂的組件。

想看看他是怎麼編譯JSX,於是我看了下用JS的寫法寫組件,主要的方法就是React.createElement

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

第一個參數type是類型,也就是名字,比如h1div自訂群組件名等~
第二個參數[props]其實就是各種屬性,我們在JS中怎麼寫屬性的,在這裡就怎麼寫。比如img.src="",div.className=""這樣的,那麼屬性就是這麼寫的{className:"",src:""},屬性名稱和JS保持一致。
第三個參數,其實就是無限延展當前節點的子節點,你想有多少個就有多少個。

來看一眼官方文檔的轉化,這個是我用React.createElement來轉義的JSX,這樣一個套一個的寫法,什麼時候才是個頭。強烈的求生欲使我放棄了JS的寫法,轉投JSX的寫法了:

相比較這種無限嵌套的寫法,JSX友善太多了。從語義化的角度來說,JSX的可讀性也是很好滴。(為自己學習JSX強行找理由。)

深入瞭解JSX的對象

上一節提到,

let element=<h1 className="aaa">A爆了</h1>//等同於let element=React.createElement(  "h1",  {className:"aaa"},  "A爆了")

那麼是不是我直接let {type,props,children}=element就可以得到 h1{className:"aaa"}A爆了了呢?我還是太天真了。type確實是h1,但是props打出來是{className: "aaa", children: "A爆了"}。咦?怎麼children混在了這裡,那麼後面得children呢?毫無疑問undefined。也就是說一個React.createElement或者JSX的對象的結構是這樣的:

{    type:"h1",    props:{        className:"aaa",        children:"A爆了"    }}
JSX的花式寫法(內含錯誤示範)

JSX有許多中寫法,看的我是眼花繚亂,不如來分析分析這些寫法的奧秘,為什麼要這麼寫,然後找一種自己喜歡的方式來寫。這裡我會以let element=XXX為例子,然後大家可以直接ReactDOM.render(element, document.getElementById('root'));這樣渲染。

寫法一:一個標籤內嵌純文字

我習慣在寫JS的時候,將這些標籤寫在字串中,然後拼接起來。看到這麼寫,真的覺得是個bug,瀏覽器一定會報錯的!然而在react中,不會報錯的,這是正確的。

let element=<h1 className="aaa">A爆了</h1>ReactDOM.render(element, document.getElementById('root'));
錯誤寫法示範:無標籤純文字

那如果是純文字呢?華麗麗地報錯了。說名JSX還是需要標籤包裹的。

let element=A爆了
寫法二:一個標籤嵌套標籤混合文字

那麼我們多加幾個子項目進,也是OK的,沒什麼毛病。

let element=<h1 className="aaa">aaa<span>A爆了</span>bbbb</h1>
寫法三:Fragment包裹所有!錯誤寫法示範:多個標籤並列

如果是很多個並列地兄弟節點呢?突然興奮!報錯了~果然不能皮。為什麼呢?大家都是正正經經的HTML標籤啊。

let element=    <h1 className="aaa">A爆了</h1>    <h1 className="aaa">A爆</h1>

官方給出的解釋是:必須包裹在一個閉合的標籤內。意思就是說不能N個閉合標籤並列嗎?

let element=<div>    <h1 className="aaa">A爆了</h1>    <h1 className="aaa">A爆</h1></div>

外面多加一層div就可以。可是這樣可能會多出很多個不需要的div啊,我們乾乾淨淨的HTML,會不會變成嵌套地獄啊。官方的求生欲也是很強的,早就想到了這一點,所以有一個官方的組件叫做Fragment。專門用於包裹這些不需要多加一層div的元素們。這個組件的用法:

//首先別忘了匯入,不然直接React.Fragment也是可以的import React,{Fragment} from 'react';//然後let element=<Fragment>    <h1 className="aaa">A爆了</h1>    <h1 className="aaa">A爆</h1></Fragment>

前面提到了element列印的結構:{type:"h1",props:{className:"aaa",children:"A爆了"}},好奇心旺盛的我列印了下<Fragment>element是什麼樣的。結果如下所示,type:Symbol(react.fragment),雖然這個根節點是特殊的標籤,不是div,p這種正正經經的HTML標籤,但也是一個節點了。也就是說element相當於一個根節點,這個根節點只能有一個,然後這個根節點可以有無數的子節點。

{    type:Symbol(react.fragment),    props:{        children:[        {type: "h1", props: {…}}        {type: "h1", props: {…}}    ]}

寫法四:數組真的不行嗎?

好奇心旺盛的我,不願意屈服於所有的外面都要加一個標籤包裹,文檔說的是一個閉合的標籤,那麼[]這樣包裹一個數組可不可以呢?wow~沒有報錯!也就是說閉合標籤不一定指代<></>也可以是[],來代表一個整體。

let element=    [        <li>1</li>,        <li>1</li>,        <li>1</li>    ]

寫法五:長的好看而已

我還看到一種寫法,就是在最外層加上()來包裹整個節點。我一開始以為這是什麼騷操作,會讓element變得與眾不同。於是,我做了個實驗,將兩個一樣的節點進行對比,不同點在於第一個無(),第二個有(),然後結果是true,也就是說他們本質上沒啥不同。所以小夥伴們,不寫()也不會報錯的。

let element=<div><h1 className="aaa">A爆了</h1><h1 className="aaa">A爆</h1></div>let element1=(<div><h1 className="aaa">A爆了</h1><h1 className="aaa">A爆</h1></div>)console.log(JSON.stringify(element1)===JSON.stringify(element))

那麼這個括弧有什麼用呢?當然有!好看!我們來看一樣Component裡面的render如果沒有()會怎麼樣。

render() {    return (        <div className="App">            <p className="App-intro">To get started, edit<code>src/App.js</code> and save to reload.</p>        </div>    )}

原本是有()的,然後可以換行,把節點排排整齊。看著也很舒服。然後我們把()去了會怎麼樣?整齊是整齊,但是會報錯啊!

render() {    return         <div className="App">        .....}

這裡就有一個小知識點,js語言設計中return的內容必須一行完成,不要跟斷行符號,不然就會報錯。(真是任性的操作)也就是說像下方這麼寫就沒有問題。但是我就沒辦法保證整整齊齊的標籤了啊!這個排版怎麼排都醜。所以這個時候()就展現出了他的魅力,代表了一個整體,告訴return我還沒結束。所以大家也不要被()給迷惑了,不要怕他。

render() {    return <div className="App">        .....}
JSX中的標籤屬性

寫JSX會發現,雖然我是在寫HTML,但是有些屬性好奇怪啊,經常寫錯,比如最常見的className。我總結出一點我們寫標籤的時候是HTML,寫屬性的時候要用JS思維。這樣就不複雜,也不難記拉!

\\JS中怎麼取class屬性的呢?document.getElementById('myid').className\\遇到特殊的<label id="label" for="xxx"></label>,這個for在JS中怎麼擷取呢?document.getElementById('label').htmlFor

那麼問題來了,有一個名為style的屬性,你要怎麼處理?style就比較複雜了,他不是一個值一個字串能夠搞定搞定的。我先在報錯的邊緣試探下吧。

試探一:字串!

let element=<div style="color:green">A爆</div>

報錯啦!報錯啦!官方提示我們Thestyleprop expects a mapping from style properties to values, not a string. For example, style={{marginRight: spacing + 'em'}} when using JSX.也就是說style需要從樣式屬性對應到他的值,字串是不可以的。所以就需要{marginRight: spacing + 'em'}像這樣的對象才可以。那為什麼要再加一層{}?

試探二:單層{}

let element=<div style={color:"green"}>A爆</div>

直接編譯錯誤了。也就是說JSX中不能直接包含JS的函數。而要用{}包裹起來JS函數。所以才有了雙層{}。第一層是代表我是JS,第二層其實就是屬性對象本身了。大家不用再試探底線了老老實實:

let element=<div style={{color:"green"}}>A爆</div>

如果想再JSX中加註釋怎麼辦?直接<!--XXX-->肯定報錯囧。我們可以用{/*XXX*/}的方式注釋,因為{}標籤裡面是js函數,我們用JS的注釋就OK拉!(其實JSX還是JS啊。)

JSX中使用JS

上文提到{}中包含的是JS,那麼我們是不是可以玩出更多的花樣的?因為{}中我們就可以用JS為所欲為了!

比如迴圈(正確):

let arr=[1,2,3]let element=(    {arr.map((v,i)=>        <div>{v}-A爆</div>    )})

如果不想迴圈直接return,可以這樣,內部加上大括弧,再繼續寫額外操作。別忘了return,只有=>函數可以省去return

let arr=[1,2,3]let element=(    <Fragment>        {arr.map((v,i)=>{            if(v===1){                return <span>A爆了</span>            }else{                return <span>B爆了</span>            }        })}    </Fragment>)

但是如果JS在標籤<></>外部的話,就可以直接使用,而不用加上{}

let element=    arr.map((v,i)=>{        if(v==1){            return <div>{v}-A爆</div>        }else{            return <div>{v}-B爆</div>        }    })

大家注意了,這裡無論如何element都是一個對象,所以賦予他的值也只能是對象。所以不能直接if/else進行操作,建議再JSX外層操作,而不是直接再JSX中的外層操作。

比如這樣,那就只能等吃紅牌了。

let element=(    if(v===1){        return <span>A爆了</span>    }else{        return <span>B爆了</span>    })

最好是這樣:

let v=1;let element;if(v===1)    element=<span>A爆了</span>}else{    element=<span>B爆了</span>}

在Comopent的render中,我麼可以這麼寫:

render() {    if(v===1){        return <span>A爆了</span>          }else{        return <span>B爆了</span>    }}

研究完之後,發現JSX就是JS啊,以及每次用JSX“文法”寫的元素,都要返回一個數組或者是對象。只要牢記這一點,就可以玩轉JSX。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.