從根本上講,JSX就是提供了一個React.createElement(component, props, ...children)
函數的語法糖。就像下面的JSX代碼:javascript
<MyButton color="blue" shadow={2}> Click Me </MyButton>
通過編譯後爲:html
React.createElement( MyButton, {color: 'blue', shadow: 2}, 'Click Me' )
若是一個標籤沒有子元素的話,你可使用/>
來自動閉合。例如:java
<div className="sidebar" />
通過編譯後爲:react
React.createElement( 'div', {className: 'sidebar'}, null )
若是你想測試一些特定的JSX是如何轉換成JavaScript的話,你能夠試試在線Babel編譯器
。數組
JSX標記的第一部分決定了React元素的類型。dom
首字母大寫的類型表示JSX標記指的爲React組件。 這些標籤被編譯爲對指定變量的直接引用,所以若是使用JSX <Foo />
表達式,Foo必須在當前的做用域內。ide
因爲JSX編譯的本質是對React.createElement
的調用,所以React庫也必須始終在JSX代碼的做用域中。
例如,雖然CustomButton
沒有直接引用React
,可是這兩個導入的模塊在這段代碼中也仍是頗有必要的:函數
import React from 'react'; import ReactDOM from 'react-dom'; function WarningButton(props) { // return React.createElement(CustomButton, {color: 'red'}, null); return <CustomButton color="red" /> }
若是不使用JavaScript打包工具並將React經過script標籤引入,那麼它就會做爲一個全局變量React
。工具
您還可使用JSX中的點表示符來引用React組件。 若是您有一個模塊會導出不少React組件的話,使用這種方法就會十分方便。 例如,若是MyComponents.DatePicker
是一個組件,您能夠直接從JSX使用它:測試
import React from 'react'; import ReactDOM from 'react-dom'; const MyComponents = { DatePicker(props) { return <div>這裏有一個顏色爲{props.color}的日期選擇器</div> } }; function BlueDataPicker(props) { return <MyComponents.DatePicker color="blue" /> } ReactDOM.render( <BlueDataPicker />, document.getElementById('root') );
當元素類型以是小寫字母開頭時,它指向一個內置組件,如<div>
或<span>
,並生成一個字符串'div'
或'span'
傳遞給React.createElement
。 以大寫字母開頭的類型,如<Foo />
編譯爲React.createElement(Foo)
,而且在當前做用域內尋找這個名稱爲Foo
的已定義或已導入組件。
咱們建議使用首字母大寫
命名組件。 若是你有一個以小寫字母開頭的組件,請在JSX中使用它以前請將它賦值給一個首字母大寫的變量。
下面代碼不會按預期運行:
import React from 'react'; //這是錯誤的,這個組件應該爲首字母大寫 function hello(props) { // 這是正確的,由於div是一個有效的html標籤 return <div>Hello {props.name}</div>; } function HelloWorld(props) { // 這是錯誤的,由於它是首字母小寫,因此React認爲<hello />是一個html標籤 return <hello name="zhangyatao" /> }
想要修復上面的問題,咱們必須將hello
重命名爲Hello
,經過<Hello />
來使用該組件:
import React from 'react'; // 這是正確的 function Hello(props) { return <div>Hello {props.name}</div>; } function HelloWorld(props) { // 這是正確的 return <Hello name="zhangyatao" />; }
不能將常規的javascript表達式用做React元素類型。 若是你想使用一個通用表達式來表示元素的類型,只需將它賦值給一個首字母大寫的變量便可。
這一般出如今當你想基於同一個props渲染一個不一樣的組件的狀況下:
import React from 'react'; import {Com1, Com2} from './Components'; const components = { myCom1: Com1, myCom2: Com2 } function RunCom(props) { // 這是錯誤的,JSX的類型不能這麼寫 return <components[props.comType] type={props.type} />; }
想要解決上面的問題,只須要將它們賦值給一個首字母大寫的變量便可:
import React from 'react'; import {Com1, Com2} from './Components'; const components = { myCom1: Com1, myCom2: Com2 } function RunCom(props) { // 這是正確的,將它們賦值給一個首字母大寫的變量 const MyCom = components[props.comType]; return <MyCom type={props.type} />; }
在JSX中指定Props有如下幾種不一樣的方法。
你能夠傳遞任何JavaScript表達式做爲Props,用{}
括住它們就可使用。 例如,在這個JSX中:
<MyComponents foo={1 + 2 + 3 + 4} />
對於MyComponent
來講,props.foo
的值將爲10
,由於是經過表達式1 + 2 + 3 + 4
計算獲得的。
if
語句和for
循環在JavaScript中不是表達式,所以它們不能在JSX中直接使用。 相反,寫完它們以後你能夠把JSX放在裏面。 例如:
function NumberDescriber(props) { let description; if (props.number % 2 === 0) { description = <strong>偶數</strong> } else { description = <strong>奇數</strong> } return <div>{props.number}是一個{description}.</div>; }
你能夠傳遞一個字符串內容做爲props。 這兩個JSX表達式是等價的:
<MyComponent message="hi zhangyatao" /> <MyComponent message={'hi zhangyatao'} />
當你傳遞一個字符串直接量時,它的值是通過html轉義的。 因此這兩個JSX表達式是等價的:
<MyComponent message='<3' /> <MyComponent message={'<3'} />
若是你沒有給Props傳入一個值,那麼它的默認值爲true
,這兩個JSX表達式是等價的:
<MyTextBox autocomplete /> <MyTextBox autocomplete={true} />
通常來講,咱們不建議使用它,由於它可使用ES6對象的簡寫{foo}
,也就是{foo:foo}
的簡稱會和{foo:true}
混淆。 這種行爲在這裏只是方便它匹配到HTML行爲。
若是你有一個對象相似的數據做爲props,而且想在JSX中傳遞它,你可使用...
做爲一個「spread」
運算符傳遞整個props對象。 這兩個組件是等效的:
function App() { return <Greeting firstName="yatao" lastName="zhang" />; } function App() { const props = {firstName: 'yatao', lastName: 'zhang'}; return <Greeting {...props} />; }
當建立一個通用容器時,spread
props頗有用。
然而,他們也可讓你的代碼變得有點凌亂,這樣很容易使大量不相關的prps傳遞給那些不關心它們的組件。 建議您謹慎使用此語法。
在包含開始標記和結束標記的JSX表達式中,這些標記之間的內容經過一種特殊的prop:props.children
傳遞。 有幾種不一樣的方式傳遞子組件:
你能夠在開始和結束標籤之間放一個字符串,那麼props.children
就是那個字符串。 這對許多內置的HTML元素頗有用。 例如:
function MyComponent(props) { return <div>{props.children}<div>; //=> <div>hello zhangyatao</div> } <MyComponent>Hello zhangyatao</MyComponent>
這是有效的JSX,而且MyComponent
中的props.children
將是字符串「Hello zhangyatao」
。 HTML標籤是不會通過轉義的,因此你通常能夠寫JSX就像你寫HTML同樣:
<div>這是一個html標籤 & 同時也是個JSX</div>
JSX會刪除行的開始和結尾處的空格。 它也會刪除中間的空行。 與標籤相鄰的空行被會被刪除;
在字符串文本中間出現的空行會縮合成一個空格。 因此這些都渲染相同的事情:
<div>hello zhangyatao</div> <div> hello zhangyatao </div> <div> hello zhangyatao </div> <div> hello zhangyatao </div>
你可使用不少個JSX元素做爲子元素。 這對須要嵌套的顯示類型組件頗有用:
<Dialog> <DialogHeader /> <DialogBody /> <DialogFooter /> </Dialog>
你能夠將不一樣類型的子元素混合在一塊兒,所以JSX子元素能夠與字符串直接量一塊兒使用。 這是JSX的另外一種方式,就像一個HTML同樣:
<div> 這是一個列表 <ul> <li>item 1</li> <li>item 2</li> </ul> </div>
一個React組件不可能返回多個React元素,可是一個JSX表達式能夠包含多個子元素,所以若是你想讓一個組件渲染多個東西,你能夠將它們統一放置在就像上面那樣的div中。
您能夠將任何JavaScript表達式放在{}
中做爲子組件傳遞。 例如,下面這些表達式是等價的:
function MyComponent(props) { return <div>{props.children}<div>; //=> <div>hi zhangyatao</div> } <MyComponent>hi zhangyatao</MyComponent> <MyComponent>{'hi zhangyatao'}</MyComponent>
這一般用於渲染任意長度的JSX表達式列表。 例如,這將渲染一個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表達式能夠與其餘類型的子元素混合使用。 這一般用於替換字符串模板:
function Hello(props) { return <div>Hello {props.name}</div>; }
一般,插入JSX中的JavaScript表達式都最終返回爲一個字符串、React元素、一個列表。
固然,props.children
能夠像任何其餘props那樣工做,它能夠傳遞任何類型的數據,並不侷限於那些告訴React應該如何渲染的東東。 例如,若是您有一個自定義組件,您能夠將props.children
做爲一個回調函數:
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}項</div>} </Repeat> ); } ReactDOM.render( <ListOfTenThings/>, document.getElementById('root') );
傳遞給自定義組件的子元素能夠是任何東西,只要在React在渲染以前,該組件將它們轉換爲能夠理解的東西便可。 這種用法並不常見,若是你想擴展JSX的其餘能力,能夠經過這個例子瞭解下它的工做原理。
false
,null
,undefined
和true
是有效的子元素,不過他們從根本上講是不參與渲染的。 這些JSX表達式將渲染處相同的東西:
<div /> <div></div> <div>{false}</div> <div>{null}</div> <div>{true}</div>
這對於有條件地呈現React元素頗有用。 若是showHeader
爲true
,那麼這個JSX只渲染一個<Header />
:
<div> {showHeader && <Header />} <Content /> </div>
若是返回一些「假的」
值就會收到一個警告,如數字0
,不過React仍然會渲染。 例如,此代碼將不會像您預期的那樣工做,由於當props.messages
是空數組時將打印0
:
<div> {props.messages.length && <Message messages={props.messages} />} </div>
想要修復上面的問題,你要肯定這個表達式在&&以前總返回布爾值
:
<div> {props.messages.length > 0 && <Message messages={props.messages} />} </div>
相反,若是你想要一個值如false
,true
,null
或undefined
出如今輸出中,你必須先將它轉換爲字符串
:
import React from 'react'; import ReactDOM from 'react-dom'; function MyVariable(props) { const myVariable = false; // 若是這裏不把false轉換爲字符串,這隻會輸出『個人javascript變量是』 const convertedVar = String(myVariable); return ( <div> 個人javascript變量是{convertedVar} </div> ); } ReactDOM.render( <MyVariable/>, document.getElementById('root') );