?
This document uses PHP Chinese website manual Release
基本上,JSX只是為React.createElement(component, props, ...children)
函數(shù)提供語法糖。JSX代碼:
<MyButton color="blue" shadowSize={2}> Click Me</MyButton>
編譯成:
React.createElement( MyButton, {color: 'blue', shadowSize: 2}, 'Click Me')
如果沒有子,您也可以使用標簽的自閉形式。所以:
<div className="sidebar" />
編譯成:
React.createElement( 'div', {className: 'sidebar'}, null)
如果你想測試一些特定的JSX如何轉換成JavaScript,你可以嘗試在線的Babel編譯器。
JSX標簽的第一部分決定了React元素的類型。
大寫字母表示JSX標記引用了React組件。這些標記會被編譯為對指定變量的直接引用,因此如果使用JSX <Foo />
表達式,則Foo
必須在范圍內(nèi)。
由于JSX編譯為調(diào)用React.createElement
,React
庫必須始終處于JSX代碼的范圍內(nèi)。
例如,這個代碼中的兩個導入都是必需的,盡管React
并CustomButton
沒有直接引用JavaScript:
import React from 'react';import CustomButton from './CustomButton'; function WarningButton() { // return React.createElement(CustomButton, {color: 'red'}, null); return <CustomButton color="red" />;}
如果您不使用JavaScript捆綁程序并從<script>
代碼加載React ,則它已經(jīng)在React
全局范圍內(nèi)。
您也可以在JSX中使用點符號來引用React組件。如果您有一個導出許多React組件的單個模塊,這很方便。例如,如果MyComponents.DatePicker
是組件,則可以直接從JSX使用它:
import React from 'react';const MyComponents = { DatePicker: function DatePicker(props) { return <div>Imagine a {props.color} datepicker here.</div>; }} function BlueDatePicker() { return <MyComponents.DatePicker color="blue" />;}
當元素類型以小寫字母開頭時,它指的是像<div>
or 這樣的內(nèi)置組件,<span>
并生成一個字符串'div'
或'span'
傳遞給它React.createElement
。以大寫字母開頭的類型,例如<Foo />
編譯React.createElement(Foo)
并對應于JavaScript文件中定義或導入的組件。
我們建議用大寫字母命名組件。如果您確實有一個以小寫字母開頭的組件,請在將它用于JSX之前將其分配給大寫變量。
例如,這段代碼不會按預期運行:
import React from 'react'; // Wrong! This is a component and should have been capitalized: function hello(props) { // Correct! This use of <div> is legitimate because div is a valid HTML tag: return <div>Hello {props.toWhat}</div>;} function HelloWorld() { // Wrong! React thinks <hello /> is an HTML tag because it's not capitalized: return <hello toWhat="World" />;}
為了解決這個問題,我們將重新命名hello
,以Hello
和使用<Hello />
提到它的時候:
import React from 'react';// Correct! This is a component and should be capitalized: function Hello(props) { // Correct! This use of <div> is legitimate because div is a valid HTML tag: return <div>Hello {props.toWhat}</div>;} function HelloWorld() { // Correct! React knows <Hello /> is a component because it's capitalized. return <Hello toWhat="World" />;}
您不能使用通用表達式作為React元素類型。如果您確實想使用通用表達式來指示元素的類型,請將其首先分配給大寫變量。當你想渲染一個基于道具的不同組件時,通常會出現(xiàn)這種情況:
import React from 'react';import { PhotoStory, VideoStory } from './stories';const components = { photo: PhotoStory, video: VideoStory};function Story(props) { // Wrong! JSX type can't be an expression. return <components[props.storyType] story={props.story} />;}
為了解決這個問題,我們首先將類型賦值給一個大寫的變量:
import React from 'react';import { PhotoStory, VideoStory } from './stories';const components = { photo: PhotoStory, video: VideoStory};function Story(props) { // Correct! JSX type can be a capitalized variable. const SpecificStory = components[props.storyType]; return <SpecificStory story={props.story} />; }
有幾種不同的方式可以在JSX中指定道具。
您可以將任何JavaScript表達式作為道具傳遞,通過將其包圍{}
。例如,在這個JSX中:
<MyComponent foo={1 + 2 + 3 + 4} />
因為MyComponent
,值的props.foo
將是10
因為表達式1 + 2 + 3 + 4
被評估。
if
語句和for
循環(huán)在JavaScript中不是表達式,所以它們不能直接在JSX中使用。相反,你可以把它們放在周圍的代碼中。例如:
function NumberDescriber(props) { let description; if (props.number % 2 == 0) { description = <strong>even</strong>; } else { description = <i>odd</i>; } return <div>{props.number} is an {description} number</div>;}
您可以在相應章節(jié)中了解有關條件渲染和循環(huán)的更多信息。
你可以傳遞一個字符串作為道具。這兩個JSX表達式是等價的:
<MyComponent message="hello world" /><MyComponent message={'hello world'} />
當你傳遞一個字符串時,它的值是HTML-unescaped。所以這兩個JSX表達式是等價的:
<MyComponent message="<3" /><MyComponent message={'<3'} />
這種行為通常不相關。這里只提到完整性。
如果您沒有為道具傳遞值,則默認為true
。這兩個JSX表達式是等價的:
<MyTextBox autocomplete /><MyTextBox autocomplete={true} />
一般來說,我們不建議使用它,因為它可能與ES6對象速記 相混淆,而速記{foo}
是簡短的,{foo: foo}
而不是{foo: true}
。這種行為就在那里,以便它符合HTML的行為。
如果你已經(jīng)有了props
一個對象,并且你想通過JSX傳遞它,你可以使用...
“spread”運算符來傳遞整個道具對象。這兩個組件是等價的:
function App1() { return <Greeting firstName="Ben" lastName="Hector" />;} function App2() { const props = {firstName: 'Ben', lastName: 'Hector'}; return <Greeting {...props} />;}
你也可以選擇你的組件將使用的特定道具,同時使用傳播運算符傳遞所有其他道具。
const Button = props => { const { kind, ...other } = props; const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton"; return <button className={className} {...other} />;}; const App = () => { return ( <div> <Button kind="primary" onClick={() => console.log("clicked!")}> Hello World! </Button> </div> );};
在上面的例子中,kind
道具被安全地消費,并且不會傳遞給<button>
DOM中的元素。所有其他道具都通過...other
對象傳遞,使得這個組件非常靈活。你可以看到,它傳遞一個onClick
和children
道具。
擴展屬性可能很有用,但它們還可以輕松地將不必要的道具傳遞給不關心它們的組件或將無效的HTML屬性傳遞給DOM。我們建議謹慎使用這種語法。
在同時包含開始標記和結束標記的JSX表達式中,這些標記之間的內(nèi)容作為特殊的道具傳遞:props.children
。有幾種不同的方式來傳遞孩子:
您可以在開始標簽和結束標簽之間放置一個字符串,并且props.children
只是該字符串。這對于許多內(nèi)置的HTML元素很有用。例如:
<MyComponent>Hello world!</MyComponent>
這是有效的JSX,并props.children
在MyComponent
將簡單地字符串"Hello world!"
。HTML是非轉義的,所以通??梢跃帉慗SX,就像您以這種方式編寫HTML一樣:
<div>This is valid HTML & JSX at the same time.</div>
JSX在行的開頭和結尾刪除空格。它也刪除空行。與標簽相鄰的新行被刪除; 發(fā)生在字符串文字中間的新行會壓縮為一個空格。所以這些都呈現(xiàn)相同的事物:
<div>Hello World</div><div> Hello World</div><div> Hello World</div><div> Hello World</div>
您可以提供更多的JSX元素作為孩子。這對于顯示嵌套組件很有用:
<MyContainer> <MyFirstComponent /> <MySecondComponent /></MyContainer>
您可以將不同類型的子項混合在一起,以便您可以將字符串文字與JSX子項一起使用。這是JSX與HTML相似的另一種方式,因此這是有效的JSX和有效的HTML:
<div> Here is a list: <ul> <li>Item 1</li> <li>Item 2</li> </ul></div>
React組件也可以返回一組元素:
render() { // No need to wrap list items in an extra element! return [ // Don't forget the keys :) <li key="A">First item</li>, <li key="B">Second item</li>, <li key="C">Third item</li>, ];}
您可以將任何JavaScript表達式作為子項傳遞,方法是將其放入其中{}
。例如,這些表達式是等價的:
<MyComponent>foo</MyComponent><MyComponent>{'foo'}</MyComponent>
這通常用于呈現(xiàn)任意長度的JSX表達式列表。例如,這呈現(xiàn)一個HTML列表:
function Item(props) { return <li>{props.message}</li>;} function TodoList() { const todos = ['finish doc', 'submit pr', 'nag dan to review']; return ( <ul> {todos.map((message) => <Item key={message} message={message} />)} </ul> );}
JavaScript表達式可以與其他類型的孩子混合使用。這通常用于替代字符串模板:
function Hello(props) { return <div>Hello {props.addressee}!</div>;}
通常,插入到JSX中的JavaScript表達式將評估為一個字符串,一個React元素或這些東西的列表。然而,props.children
就像任何其他道具一樣,它可以傳遞任何類型的數(shù)據(jù),而不僅僅是React知道如何渲染的種類。例如,如果你有一個自定義組件,你可以讓它回調(diào)為props.children
:
// Calls the children callback numTimes to produce a repeated component function Repeat(props) { let items = []; for (let i = 0; i < props.numTimes; i++) { items.push(props.children(i)); } return <div>{items}</div>;}function ListOfTenThings() { return ( <Repeat numTimes={10}> {(index) => <div key={index}>This is item {index} in the list</div>} </Repeat> ); }
傳遞給自定義組件的子項可以是任何東西,只要該組件將它們轉換為React在呈現(xiàn)之前可以理解的內(nèi)容即可。這種用法并不常見,但如果您想要擴展JSX的功能,它就可以工作。
false
,null
,undefined
,和true
有效的兒童。他們根本不渲染。這些JSX表達式都將呈現(xiàn)相同的事物:
<div /><div></div><div>{false}</div><div>{null}</div><div>{undefined}</div><div>{true}</div>
這有助于有條件地呈現(xiàn)React元素。這JSX只呈現(xiàn)一個<Header />
,如果showHeader
是true
:
<div> {showHeader && <Header />} <Content /></div>
有一點需要注意的是,一些“虛假”的價值觀,如0
數(shù)字,仍然由React渲染。例如,這段代碼不會像你所期望的那樣工作,因為0
當它props.messages
是一個空數(shù)組的時候會被打印出來:
<div> {props.messages.length && <MessageList messages={props.messages} /> }</div>
要解決這個問題,請確保前面的表達式&&
始終是布爾值:
<div> {props.messages.length > 0 && <MessageList messages={props.messages} /> }</div>
相反,如果你想有一個類似的值false
,true
,null
,或undefined
出現(xiàn)在輸出中,你必須把它轉換為字符串第一:
<div> My JavaScript variable is {String(myVariable)}.</div>