學習React,從攻克JSX開始

詳情參考官方JSX規範html

雖然JSX是擴展到ECMAScript的類XML語法,可是它自己並無定義任何語義。也就是說它自己不在ECMAScript標準範圍以內。它也不會被引擎或者瀏覽器直接執行。一般會利用很編譯器預處理器來將這些JSX轉化爲標準的ECMAScript。react

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

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

React.createElement(
  type,
  [props],
  [...children]
)
複製代碼

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

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

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

深刻了解JSX的對象

上一節提到,bash

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的對象的結構是這樣的:app

{
    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。

相關文章
相關標籤/搜索