- React工程師修煉指南
- 開課吧組編 高少云 莫濤 韓明洋 余維海編著
- 2688字
- 2021-04-14 11:28:45
2.3 React視圖渲染
構(gòu)建視圖一直是React的重點(diǎn),從createElement到JSX,React構(gòu)建視圖的方法一直深受開發(fā)者喜愛。
2.3.1 ReactElement
當(dāng)需要用React創(chuàng)建虛擬DOM時(shí),React專門提供了一個(gè)方法createElement()。注意該方法并非是原生DOM中的createElement。具體使用方法如下:

該方法區(qū)別于上文中講的ReactDOM,它屬于React對(duì)象,不要混淆。利用createElement方法,就可以來(lái)創(chuàng)建ReactElement,也就是React中的虛擬DOM。具體參數(shù)如下。
1)type要?jiǎng)?chuàng)建的標(biāo)簽類型。如要?jiǎng)?chuàng)建的是個(gè)div標(biāo)簽,則寫React.createElement("div"),一定注意type的類型是一個(gè)字符串。
2)congfig參數(shù)是設(shè)置生成的節(jié)點(diǎn)的相關(guān)屬性,這里要注意congfig的類型是一個(gè)純對(duì)象,具體代碼如下:


在使用congfig的時(shí)候,有兩個(gè)問(wèn)題需要注意。
①?zèng)]有屬性需要定義,但又需要傳遞children參數(shù)時(shí),congfig可以給null,React.createElement("h1",null,"hello React")。
②congfig中有兩個(gè)固定的參數(shù)key和ref,最好不要亂用,后續(xù)章節(jié)會(huì)詳細(xì)講到。
3)children代表該元素的內(nèi)容或者子元素。具體有三種不同的寫法。
①children是字符串時(shí),則代表在元素里添加文本內(nèi)容,如:
React.createElement("h1",null,"hello React"),最終渲染到DOM里的內(nèi)容為

②children是數(shù)組時(shí),則會(huì)把數(shù)組中的內(nèi)容展開放入元素中,如:
React.createElement("h1",null,["hello React"]),最終渲染到DOM里的內(nèi)容為

當(dāng)然這里也可以在數(shù)組中放入新的ReactElement,具體代碼如下:

最終生成結(jié)果如下:

③children是ReactElement時(shí),會(huì)直接當(dāng)作元素的子節(jié)點(diǎn)進(jìn)行添加。需要添加多個(gè)子元素時(shí),可以一直跟在后邊寫。具體代碼如下:

上述代碼的展示效果跟數(shù)組的案例并沒有什么不同,就不再過(guò)多復(fù)述。通過(guò)createElement已經(jīng)可以正常來(lái)構(gòu)建視圖了,但是利用createElement構(gòu)建視圖時(shí),如果視圖結(jié)構(gòu)特別復(fù)雜,寫起來(lái)就特別麻煩,而且結(jié)果極其不清晰。具體代碼如下:

生成結(jié)果如下:

通過(guò)上述demo可以看到一個(gè)比較復(fù)雜視圖的編寫,但是這種代碼從層級(jí)結(jié)構(gòu)上來(lái)看極其不清晰,所以在真正開發(fā)時(shí)不推薦使用ReactElement的這種方式來(lái)編寫視圖。React中提供了一個(gè)編寫視圖的神器JSX。
2.3.2 JSX
JSX是什么呢?展開來(lái)說(shuō)就是JavaScript+XML,是一個(gè)看起來(lái)很像XML的JavaScript語(yǔ)法擴(kuò)展。具體代碼如下:

從上述示例中可以看到,可以直接在JS中利用前端開發(fā)者熟悉的html標(biāo)簽來(lái)構(gòu)建視圖,這樣的代碼結(jié)構(gòu)層級(jí)非常清晰,也便于維護(hù),當(dāng)然上手也更便捷。但是在使用JSX的時(shí)候,還有些問(wèn)題需要開發(fā)人員注意。
JSX是JS的語(yǔ)法擴(kuò)展,但是瀏覽器并不識(shí)別這些擴(kuò)展,所以需要借助babel.js來(lái)對(duì)JSX進(jìn)行編譯,使其成為瀏覽器識(shí)別的語(yǔ)法,也就是React.createElement,具體用法如下:

這里有兩點(diǎn)需要注意:使用JSX時(shí)必須引用babel對(duì)代碼進(jìn)行編譯;該script標(biāo)簽內(nèi)的代碼需要使用babel編譯時(shí),必須設(shè)置type="text/babel"。上述代碼經(jīng)過(guò)babel編譯之后的代碼如下:

JSX本身是一個(gè)值,這個(gè)值是一個(gè)ReactElement,而非字符串。在編寫的時(shí)候一定要注意,如果給一個(gè)字符串類型的值時(shí),代碼如下:

最終在視圖上h1并不會(huì)被解析成一個(gè)標(biāo)簽,而是解析成文本內(nèi)容。這里主要是因?yàn)镴SX在解析的時(shí)候會(huì)被編譯,字符串內(nèi)容會(huì)進(jìn)行轉(zhuǎn)義,這樣在設(shè)置innerHTML的時(shí)候,就不會(huì)被解析成標(biāo)簽了,最終呈現(xiàn)結(jié)果如圖2-3所示。

●圖2-3 最終呈現(xiàn)結(jié)果
1.插值表達(dá)式
使用JSX時(shí),如果需要視圖和數(shù)據(jù)進(jìn)行綁定,就需要使用插值表達(dá)式,也就是在視圖中去插入數(shù)據(jù)。寫法跟ES6中的模板字符串類似,不過(guò)用的是{數(shù)據(jù)},而非${數(shù)據(jù)}。示例如下:

在使用插值表達(dá)式時(shí),要注意以下幾個(gè)問(wèn)題。
1){}中,接收一個(gè)JS表達(dá)式,可以是運(yùn)算式,變量或函數(shù)調(diào)用等。表達(dá)式的意思就是這個(gè)語(yǔ)句一定會(huì)有一個(gè)值返回,而插值的意思就是把表達(dá)式計(jì)算得到的值插入到視圖中去。
2){}中,接收的是函數(shù)調(diào)用時(shí),該函數(shù)需要有返回值。明確了{(lán)}中可以放什么樣的代碼之后,再來(lái)看看各種不同類型的數(shù)據(jù),在插值之后去渲染視圖的表現(xiàn)。
3)字符串、數(shù)字:原樣輸出。如:

最后可以得到:

4)布爾值、空、未定義:輸出空值,也不會(huì)有錯(cuò)誤。如:

最后可以得到:

5)數(shù)組:支持直接輸出,默認(rèn)情況下把數(shù)組的連接符“,”替換成空,然后直接輸出。如下例:

輸出結(jié)果為

6)對(duì)象:不能直接輸出,但是可以通過(guò)其他方式,如Object.values、Object.keys等方法去解析對(duì)象,轉(zhuǎn)換成數(shù)組之后進(jìn)行輸出。示例如下:

輸出結(jié)果為

了解了不同類型的數(shù)據(jù)在插值中的輸出之后,來(lái)學(xué)習(xí)一些比較特殊的渲染情況。
1)列表渲染。所謂的列表渲染,就是需要把數(shù)據(jù)批量渲染到JSX中,示例如下:

輸出結(jié)果為

這里利用JSX可以插入數(shù)組的特性,利用數(shù)組在這里進(jìn)行批量渲染。在開發(fā)環(huán)境下有些用戶可能會(huì)看到這里有一個(gè)關(guān)于key的錯(cuò)誤,這個(gè)問(wèn)題在后面的章節(jié)會(huì)詳細(xì)地進(jìn)行講解。
2)條件渲染。有些時(shí)候,React需要根據(jù)不同的情況來(lái)渲染不同的內(nèi)容,但是在插值中不能直接使用if語(yǔ)句,該怎么處理這個(gè)問(wèn)題?有以下幾種選擇。
①&&與運(yùn)算符。&&運(yùn)算有一個(gè)特征,左側(cè)的運(yùn)算結(jié)果為true時(shí)返回右側(cè)內(nèi)容。示例如下:


在該示例中,如果age的數(shù)值>=18才會(huì)輸出:

否則不做任何輸出。
②‖或運(yùn)算符。‖運(yùn)算的特征和&&相反,左側(cè)的運(yùn)算結(jié)果為false時(shí),返回右側(cè)內(nèi)容。如下:

在該示例中,如果age的數(shù)值>=18不做任何輸出,否則輸出:

③三目運(yùn)算。示例如下:

在示例中,如果age>=18則輸出:

否則輸出:

④在邏輯特別復(fù)雜的情況下,也可以借用函數(shù)。在函數(shù)里進(jìn)行相關(guān)的處理,最后把處理結(jié)果返回即可。示例如下:


2.JSX屬性書寫
通過(guò)JSX已經(jīng)可以正常去編寫視圖了,但編寫視圖時(shí)肯定還需要去添加一些相應(yīng)的屬性,如class、id、type等。但要注意JSX并不是真正的HTML,所以書寫時(shí)還是有一些注意事項(xiàng)。
1)所有的屬性名都使用駝峰命名法。
2)如果屬性值是字符串并且是固定不變的,則可以直接寫,如:

3)如果屬性值是非字符串類型,或者是動(dòng)態(tài)的,則必須用插值表單式。如:

4)有一些特殊的屬性名并不能直接用,具體如下:
①class屬性改為className。如:

②for屬性改為htmlFor。
③colspan屬性改為colSpan。
5)style在書寫的時(shí)候要注意它接收的值是個(gè)對(duì)象,示例如下:

這里可以看到style的值是個(gè)插值,接收的是一個(gè)對(duì)象。除了單獨(dú)聲明變量外,也可以直接簡(jiǎn)寫成下例所示:


這里是直接把對(duì)象寫進(jìn)了插值里。
3.JSX注意事項(xiàng)
前文中詳細(xì)講解了JSX的使用,不過(guò)真正使用JSX的時(shí)候,還需要注意它的一些問(wèn)題,下面對(duì)JSX的使用問(wèn)題進(jìn)行一個(gè)匯總。
1)瀏覽器并不支持JSX,在使用時(shí)要使用babel編譯。
2)JSX不要寫成字符串,否則標(biāo)簽會(huì)被當(dāng)作文本直接輸出。
3)JSX是一個(gè)值,在輸出時(shí)只能有一個(gè)頂層標(biāo)簽,示例如下:

該例子中,JSX輸出了三個(gè)頂層標(biāo)簽header、div、footer,這樣運(yùn)行時(shí)就會(huì)報(bào)錯(cuò)。如果JSX的頂層標(biāo)簽不希望在DOM中被解析出來(lái),則可以使用<React.Fragment></React.Fragment>作為頂層標(biāo)簽。Fragment是React提供的一個(gè)容器組件,它本身并不會(huì)在真實(shí)的DOM中渲染出來(lái)。利用Fragment對(duì)上述案例進(jìn)行修改,具體代碼如下:


最終渲染出來(lái)的真實(shí)DOM如下:

4)所有的標(biāo)簽名字都必須小寫。
5)無(wú)論單標(biāo)簽還是雙標(biāo)簽都必須閉合。
6)JSX并不是HTML,在書寫時(shí)很多屬性的寫法不一樣。
①屬性名都必須遵循駝峰命名法,從第二個(gè)單詞開始首字母大寫。
②個(gè)別屬性的屬性名寫法有變化,具體參考2.3.2節(jié)。
③style的值接收的是一個(gè)對(duì)象。
7)在JSX中,插入數(shù)據(jù)需要用插值表達(dá)式{數(shù)據(jù)}
- 邊緣計(jì)算技術(shù)與應(yīng)用
- 未解之謎(下)
- 先進(jìn)PID控制MATLAB仿真(第5版)
- DSP原理及應(yīng)用:TMS320DM6437架構(gòu)、指令、功能模塊、程序設(shè)計(jì)及案例分析
- 圖解電子技術(shù)速學(xué)速用
- Android底層開發(fā)技術(shù)實(shí)戰(zhàn)詳解
- 電子產(chǎn)品組裝技能演練
- 高速電路PCB設(shè)計(jì)與EMC技術(shù)分析
- Cadence Allegro 17.4電子設(shè)計(jì)速成實(shí)戰(zhàn)寶典
- 智能電網(wǎng)技術(shù):面向供需互動(dòng)能量?jī)?yōu)化
- 第一行代碼:Android(第3版)
- 數(shù)字視頻創(chuàng)意設(shè)計(jì)與實(shí)現(xiàn)(第二版)
- 通用數(shù)字集成電路簡(jiǎn)明速查手冊(cè)
- 光電定位與光電對(duì)抗
- 數(shù)字信號(hào)處理