javascript
React从入门到精通系列之(12)深入理解JSX
十二、深入理解JSX
從根本上講,JSX就是提供了一個(gè)React.createElement(component, props, ...children)函數(shù)的語(yǔ)法糖。就像下面的JSX代碼:
<MyButton color="blue" shadow={2}>Click Me </MyButton>經(jīng)過(guò)編譯后為:
React.createElement(MyButton,{color: 'blue', shadow: 2},'Click Me' )如果一個(gè)標(biāo)簽沒(méi)有子元素的話,你可以使用/>來(lái)自動(dòng)閉合。例如:
<div className="sidebar" />經(jīng)過(guò)編譯后為:
React.createElement('div',{className: 'sidebar'},null )如果你想測(cè)試一些特定的JSX是如何轉(zhuǎn)換成JavaScript的話,你可以試試在線Babel編譯器。
指定React元素類型
JSX標(biāo)記的第一部分決定了React元素的類型。
首字母大寫的類型表示JSX標(biāo)記指的為React組件。 這些標(biāo)簽被編譯為對(duì)指定變量的直接引用,因此如果使用JSX <Foo />表達(dá)式,Foo必須在當(dāng)前的作用域內(nèi)。
React必須在作用域內(nèi)
由于JSX編譯的本質(zhì)是對(duì)React.createElement的調(diào)用,因此React庫(kù)也必須始終在JSX代碼的作用域中。
例如,雖然CustomButton沒(méi)有直接引用React,但是這兩個(gè)導(dǎo)入的模塊在這段代碼中也還是很有必要的:
如果不使用JavaScript打包工具并將React通過(guò)script標(biāo)簽引入,那么它就會(huì)作為一個(gè)全局變量React。
對(duì)JSX類型使用『點(diǎn)』表示符
您還可以使用JSX中的點(diǎn)表示符來(lái)引用React組件。 如果您有一個(gè)模塊會(huì)導(dǎo)出很多React組件的話,使用這種方法就會(huì)十分方便。 例如,如果MyComponents.DatePicker是一個(gè)組件,您可以直接從JSX使用它:
import React from 'react'; import ReactDOM from 'react-dom';const MyComponents = {DatePicker(props) {return <div>這里有一個(gè)顏色為{props.color}的日期選擇器</div>} };function BlueDataPicker(props) {return <MyComponents.DatePicker color="blue" /> }ReactDOM.render(<BlueDataPicker />,document.getElementById('root') );用戶自定義組件必須是首字母大寫
當(dāng)元素類型以是小寫字母開頭時(shí),它指向一個(gè)內(nèi)置組件,如<div>或<span>,并生成一個(gè)字符串'div'或'span'傳遞給React.createElement。 以大寫字母開頭的類型,如<Foo />編譯為React.createElement(Foo),并且在當(dāng)前作用域內(nèi)尋找這個(gè)名稱為Foo的已定義或已導(dǎo)入組件。
我們建議使用首字母大寫命名組件。 如果你有一個(gè)以小寫字母開頭的組件,請(qǐng)?jiān)贘SX中使用它之前請(qǐng)將它賦值給一個(gè)首字母大寫的變量。
下面代碼不會(huì)按預(yù)期運(yùn)行:
import React from 'react';//這是錯(cuò)誤的,這個(gè)組件應(yīng)該為首字母大寫 function hello(props) {// 這是正確的,因?yàn)閐iv是一個(gè)有效的html標(biāo)簽return <div>Hello {props.name}</div>; }function HelloWorld(props) {// 這是錯(cuò)誤的,因?yàn)樗鞘鬃帜感?#xff0c;所以React認(rèn)為<hello />是一個(gè)html標(biāo)簽return <hello name="zhangyatao" /> }想要修復(fù)上面的問(wèn)題,我們必須將hello重命名為Hello,通過(guò)<Hello />來(lái)使用該組件:
import React from 'react';// 這是正確的 function Hello(props) {return <div>Hello {props.name}</div>; }function HelloWorld(props) {// 這是正確的return <Hello name="zhangyatao" />; }在運(yùn)行的時(shí)候選擇組件類型
不能將常規(guī)的javascript表達(dá)式用作React元素類型。 如果你想使用一個(gè)通用表達(dá)式來(lái)表示元素的類型,只需將它賦值給一個(gè)首字母大寫的變量即可。
這通常出現(xiàn)在當(dāng)你想基于同一個(gè)props渲染一個(gè)不同的組件的情況下:
想要解決上面的問(wèn)題,只需要將它們賦值給一個(gè)首字母大寫的變量即可:
import React from 'react'; import {Com1, Com2} from './Components';const components = {myCom1: Com1,myCom2: Com2 }function RunCom(props) {// 這是正確的,將它們賦值給一個(gè)首字母大寫的變量const MyCom = components[props.comType];return <MyCom type={props.type} />; }JSX中的Props
在JSX中指定Props有以下幾種不同的方法。
JavaScript表達(dá)式
你可以傳遞任何JavaScript表達(dá)式作為Props,用{}括住它們就可以使用。 例如,在這個(gè)JSX中:
<MyComponents foo={1 + 2 + 3 + 4} />對(duì)于MyComponent來(lái)說(shuō),props.foo的值將為10,因?yàn)槭峭ㄟ^(guò)表達(dá)式1 + 2 + 3 + 4計(jì)算得到的。
if語(yǔ)句和for循環(huán)在JavaScript中不是表達(dá)式,因此它們不能在JSX中直接使用。 相反,寫完它們之后你可以把JSX放在里面。 例如:
function NumberDescriber(props) {let description;if (props.number % 2 === 0) {description = <strong>偶數(shù)</strong>} else {description = <strong>奇數(shù)</strong>}return <div>{props.number}是一個(gè){description}.</div>; }字符串直接量
你可以傳遞一個(gè)字符串內(nèi)容作為props。 這兩個(gè)JSX表達(dá)式是等價(jià)的:
<MyComponent message="hi zhangyatao" /><MyComponent message={'hi zhangyatao'} />當(dāng)你傳遞一個(gè)字符串直接量時(shí),它的值是經(jīng)過(guò)html轉(zhuǎn)義的。 所以這兩個(gè)JSX表達(dá)式是等價(jià)的:
<MyComponent message='<3' /><MyComponent message={'<3'} />Props默認(rèn)值為true
如果你沒(méi)有給Props傳入一個(gè)值,那么它的默認(rèn)值為true,這兩個(gè)JSX表達(dá)式是等價(jià)的:
<MyTextBox autocomplete /><MyTextBox autocomplete={true} />一般來(lái)說(shuō),我們不建議使用它,因?yàn)樗梢允褂肊S6對(duì)象的簡(jiǎn)寫{foo},也就是{foo:foo}的簡(jiǎn)稱會(huì)和{foo:true}混淆。 這種行為在這里只是方便它匹配到HTML行為。
Props傳遞
如果你有一個(gè)對(duì)象類似的數(shù)據(jù)作為props,并且想在JSX中傳遞它,你可以使用...作為一個(gè)“spread”運(yùn)算符傳遞整個(gè)props對(duì)象。 這兩個(gè)組件是等效的:
function App() {return <Greeting firstName="yatao" lastName="zhang" />; }function App() {const props = {firstName: 'yatao', lastName: 'zhang'};return <Greeting {...props} />; }當(dāng)創(chuàng)建一個(gè)通用容器時(shí),spread props很有用。
然而,他們也可以讓你的代碼變得有點(diǎn)凌亂,這樣很容易使大量不相關(guān)的prps傳遞給那些不關(guān)心它們的組件。 建議您謹(jǐn)慎使用此語(yǔ)法。
JSX中的子元素和子組件
在包含開始標(biāo)記和結(jié)束標(biāo)記的JSX表達(dá)式中,這些標(biāo)記之間的內(nèi)容通過(guò)一種特殊的prop:props.children傳遞。 有幾種不同的方式傳遞子組件:
字符串直接量
你可以在開始和結(jié)束標(biāo)簽之間放一個(gè)字符串,那么props.children就是那個(gè)字符串。 這對(duì)許多內(nèi)置的HTML元素很有用。 例如:
function MyComponent(props) {return <div>{props.children}<div>; //=> <div>hello zhangyatao</div> }<MyComponent>Hello zhangyatao</MyComponent>這是有效的JSX,并且MyComponent中的props.children將是字符串“Hello zhangyatao”。 HTML標(biāo)簽是不會(huì)經(jīng)過(guò)轉(zhuǎn)義的,所以你一般可以寫JSX就像你寫HTML一樣:
<div>這是一個(gè)html標(biāo)簽 & 同時(shí)也是個(gè)JSX</div>JSX會(huì)刪除行的開始和結(jié)尾處的空格。 它也會(huì)刪除中間的空行。 與標(biāo)簽相鄰的空行被會(huì)被刪除;
在字符串文本中間出現(xiàn)的空行會(huì)縮合成一個(gè)空格。 所以這些都渲染相同的事情:
JSX子元素
你可以使用很多個(gè)JSX元素作為子元素。 這對(duì)需要嵌套的顯示類型組件很有用:
<Dialog><DialogHeader /><DialogBody /><DialogFooter /> </Dialog>你可以將不同類型的子元素混合在一起,因此JSX子元素可以與字符串直接量一起使用。 這是JSX的另一種方式,就像一個(gè)HTML一樣:
<div>這是一個(gè)列表<ul><li>item 1</li><li>item 2</li></ul> </div>一個(gè)React組件不可能返回多個(gè)React元素,但是一個(gè)JSX表達(dá)式可以包含多個(gè)子元素,因此如果你想讓一個(gè)組件渲染多個(gè)東西,你可以將它們統(tǒng)一放置在就像上面那樣的div中。
Javascript表達(dá)式
您可以將任何JavaScript表達(dá)式放在{}中作為子組件傳遞。 例如,下面這些表達(dá)式是等價(jià)的:
function MyComponent(props) {return <div>{props.children}<div>; //=> <div>hi zhangyatao</div> }<MyComponent>hi zhangyatao</MyComponent><MyComponent>{'hi zhangyatao'}</MyComponent>這通常用于渲染任意長(zhǎng)度的JSX表達(dá)式列表。 例如,這將渲染一個(gè)HTML列表:
function Item(props) {return <li>{props.message}</li>; }function TodoList(props) {const todos = ['完成文檔', '出去逛街', '打一局dota'];return (<ul>{todos.map(message => <Item key={message} message={message} />)}</ul>); }JavaScript表達(dá)式可以與其他類型的子元素混合使用。 這通常用于替換字符串模板:
function Hello(props) {return <div>Hello {props.name}</div>; }使用函數(shù)作為子元素
通常,插入JSX中的JavaScript表達(dá)式都最終返回為一個(gè)字符串、React元素、一個(gè)列表。
當(dāng)然,props.children可以像任何其他props那樣工作,它可以傳遞任何類型的數(shù)據(jù),并不局限于那些告訴React應(yīng)該如何渲染的東東。 例如,如果您有一個(gè)自定義組件,您可以將props.children作為一個(gè)回調(diào)函數(shù):
import React from 'react'; import ReactDOM from 'react-dom';function Repeat(props) {let items = [];let callback = props.children;var numTimes = props.numTimes;for(var i = 0 ; i < numTimes ; i++ ){items.push(callback(i));}return <div>{items}</div>; }function ListOfTenThings(props) {return (<Repeat numTimes={10}>{index => <div key={index}>這是列表中的第{index}項(xiàng)</div>}</Repeat>); } ReactDOM.render(<ListOfTenThings/>,document.getElementById('root') );傳遞給自定義組件的子元素可以是任何東西,只要在React在渲染之前,該組件將它們轉(zhuǎn)換為可以理解的東西即可。 這種用法并不常見,如果你想擴(kuò)展JSX的其他能力,可以通過(guò)這個(gè)例子了解下它的工作原理。
布爾值、null、undefined在渲染時(shí)會(huì)被自動(dòng)忽略
false,null,undefined和true是有效的子元素,不過(guò)他們從根本上講是不參與渲染的。 這些JSX表達(dá)式將渲染處相同的東西:
<div /><div></div><div>{false}</div><div>{null}</div><div>{true}</div>這對(duì)于有條件地呈現(xiàn)React元素很有用。 如果showHeader為true,那么這個(gè)JSX只渲染一個(gè)<Header />:
<div>{showHeader && <Header />}<Content /> </div>如果返回一些“假的”值就會(huì)收到一個(gè)警告,如數(shù)字0,不過(guò)React仍然會(huì)渲染。 例如,此代碼將不會(huì)像您預(yù)期的那樣工作,因?yàn)楫?dāng)props.messages是空數(shù)組時(shí)將打印0:
<div>{props.messages.length && <Message messages={props.messages} />} </div>想要修復(fù)上面的問(wèn)題,你要確定這個(gè)表達(dá)式在&&之前總返回布爾值:
<div>{props.messages.length > 0 && <Message messages={props.messages} />} </div>相反,如果你想要一個(gè)值如false,true,null或undefined出現(xiàn)在輸出中,你必須先將它轉(zhuǎn)換為字符串:
import React from 'react'; import ReactDOM from 'react-dom';function MyVariable(props) {const myVariable = false;// 如果這里不把false轉(zhuǎn)換為字符串,這只會(huì)輸出『我的javascript變量是』const convertedVar = String(myVariable);return (<div>我的javascript變量是{convertedVar}</div>); } ReactDOM.render(<MyVariable/>,document.getElementById('root') );總結(jié)
以上是生活随笔為你收集整理的React从入门到精通系列之(12)深入理解JSX的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: LBaaS 实现机制 - 每天5分钟玩转
- 下一篇: 【swift3.0】【枚举定义的不同方式