深入jsx
從本質(zhì)上來說肩杈,jsx只是為React.creatElement(component,props)
提供的語法糖杏愤。例如:
<Mybutton color="blue" shadowsize={2}>
click me
</Mybutton>
編譯后得到(也就是React底層實(shí)現(xiàn)的過程):
React.createElement(
Mybutton,//組件名
{color:"blue",shadowsize:2},//相關(guān)屬性
"click me" //文本內(nèi)容
)
如果節(jié)點(diǎn)中沒有子代。子節(jié)點(diǎn)推掸,還可以直接使用自閉和標(biāo)簽桶蝎。如:
<div className="sidebar" />
然后編譯為:
React.createElement(
'div',
{className:"sidebar"},
null
)
如果你想徹底驗(yàn)證 JSX 是如何轉(zhuǎn)換為 JavaScript 的,你可以嘗試 在線 Babel 編譯器.
指定React元素類型
jsx的標(biāo)簽名決定了React的元素類型谅畅。
大寫開頭的jsx標(biāo)簽表示一個(gè)React組件登渣。這些標(biāo)簽會(huì)被編譯成同名的變量然后引用。如果你使用<Kolento />
毡泻,就必須在作用域中生命Kolento變量胜茧。
React必須聲明
由于jsx在編譯后會(huì)調(diào)用React.createElement()
方法,所以你的jsx中必須首先聲明React變量仇味,否則就找不到React了呻顽。
例如:下面的聲明都是必須的。
盡管React和CustomButton都沒有被直接調(diào)用丹墨。
import React from 'react';
import CustomButton from './CustomButton';
function WarningButton(){
// 返回 React.createElement(CustomButton, {color: 'blue'}, null);
return <CustomButton color="blue" />
}
如果使用script
加載React廊遍,他會(huì)作用于全局
點(diǎn)表示法
我們還可以使用React中的點(diǎn)表示法來引用React組件。你可以方便的從一個(gè)模塊中贩挣,導(dǎo)出許多React組件喉前,有一個(gè)叫Components.DatePicker
的組件⊥醪疲可以直接在jsx中使用它卵迂。
調(diào)用的時(shí)候只要Components.DatePicker
即可
const MyComponents = {
DatePicker:function Date(props){
return <div>Imagine a {props.color} datepicker here</div>
}
}
function BlueDatePicker(){
return <MyComponents.DatePicker color="blue" />
}
首字母大寫
當(dāng)元素的首字母以小寫開頭,則表示他是一個(gè)內(nèi)置的組件绒净,如div
span
见咒,并將字符串 ‘div’ 或 ‘span’ 傳 遞給 React.createElement。 以大寫字母開頭的類型挂疆,如 <Foo /> 編譯為 React.createElement(Foo)
改览,并它正對(duì)應(yīng)于你在 JavaScript 文件中定義或?qū)氲慕M件。
我們建議用大寫開頭命名組件缤言。如果你的組件以小寫字母開頭宝当,請(qǐng)?jiān)?JSX 中使用之前其賦值給大寫開頭的變量。
錯(cuò)誤demo
import React from 'react';
// 錯(cuò)誤墨闲!組件名應(yīng)該首字母大寫:
function hello(props) {
// 正確今妄!div 是有效的 HTML 標(biāo)簽:
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// 錯(cuò)誤郑口!React 會(huì)將小寫開頭的標(biāo)簽名認(rèn)為是 HTML 原生標(biāo)簽:
return <hello toWhat="World" />;
}
為了解決這個(gè)問題鸳碧,我們將 hello 重命名為 Hello盾鳞,然后使用 <Hello /> 引用:
import React from 'react';
// 正確!組件名應(yīng)該首字母大寫:
function Hello(props) {
// 正確瞻离!div 是有效的 HTML 標(biāo)簽:
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// 正確腾仅!React 能夠?qū)⒋髮戦_頭的標(biāo)簽名認(rèn)為是 React 組件。
return <Hello toWhat="World" />;
}
在運(yùn)行時(shí)選擇類型
我們不能使用表達(dá)式來作為React的標(biāo)簽套利,如果想用表達(dá)式的方式確定React的元素類型推励,要將表達(dá)式賦值給一個(gè)大寫開頭的標(biāo)量,這種情況一般會(huì)在條件渲染的時(shí)候出現(xiàn)肉迫。
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// 錯(cuò)誤验辞!JSX 標(biāo)簽名不能為一個(gè)表達(dá)式。
return <components[props.storyType] story={props.story} />;
}
以上demo 使用表達(dá)式去輸出一個(gè)標(biāo)簽喊衫,這是不可行的跌造,需要將components[props.storyType]賦值給一個(gè)大寫開頭的變量替換進(jìn)去才行。
解決:要解決這個(gè)問題族购,我們需要先將類型賦值給大寫開頭的變量壳贪。
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// 正確!JSX 標(biāo)簽名可以為大寫開頭的變量寝杖。
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}
屬性
在jsx中有幾種不同的方式來指定屬性
使用js表達(dá)式
可以傳遞任何{}
包裹的javascript表達(dá)式作為一個(gè)屬性值违施。
<MyComponent foo={1 + 2 + 3 + 4} />
對(duì)于MyComponent
來說,props.foo
的值為10瑟幕,是通過表達(dá)式1+2+3+4計(jì)算出來的磕蒲。
if
語句和for
循環(huán)在js中不是表達(dá)式,因此不能再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>;
}
你可以在相關(guān)部分中了解有關(guān) 條件渲染 和 循環(huán) 的更多信息。
字符串常量
可以將字符串常量作為屬性傳遞鹿霸,以下的2個(gè)jsx是等價(jià)的排吴。
<MyComponents message={"hello"} />
<MyComponents message="hello" />
當(dāng)傳遞一個(gè)字符串常量時(shí),該值會(huì)被解析為HTML非轉(zhuǎn)義字符串懦鼠,所以下面兩個(gè) JSX 表達(dá)式是相同的:
<MyComponent message="<3" />
<MyComponent message={'<3'} />
以上的這點(diǎn)钻哩,了解一下即可。
屬性默認(rèn)為true
如果你沒有給屬性傳值肛冶,則他默認(rèn)為true街氢,因此一下2個(gè)jsx表達(dá)式是等價(jià)的。
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />
一般情況下睦袖,我們不建議這樣使用珊肃,因?yàn)樗鼤?huì)與 ES6 對(duì)象簡(jiǎn)潔表示法 混淆。比如 {foo}
是 {foo: foo}
的簡(jiǎn)寫,而不是 {foo: true}
伦乔。這里能這樣用厉亏,是因?yàn)樗?HTML 的做法。
擴(kuò)展屬性
如果你已經(jīng)有了props對(duì)象烈和,并且想在jsx中傳遞他爱只,可以使用...
作為擴(kuò)展操作符來傳遞整個(gè)對(duì)象。以下的2個(gè)組件是等價(jià)的招刹。
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2(){
const props = {firstName:"Ben",lastName="Hector"}
return <Greeting {...props}>
}
當(dāng)你構(gòu)建通用容器時(shí)恬试,擴(kuò)展屬性會(huì)非常有用。然而疯暑,這樣做也可能讓很多不相關(guān)的屬性训柴,傳遞到不需要它們的組件中使代碼變得混亂。我們建議你謹(jǐn)慎使用此語法妇拯。
子代
在包含開始與結(jié)束標(biāo)簽之間的jsx表達(dá)式中畦粮,標(biāo)記之間的內(nèi)容可以作為特殊的參數(shù)傳遞props.children
,有幾種不同的方法來傳遞子代乖阵。
也就是說props.children
指代標(biāo)簽中的內(nèi)容宣赔。
字符串常量
你可以在開始和結(jié)束標(biāo)簽之間放入一個(gè)字符串,則 props.children
就是那個(gè)字符串瞪浸。這對(duì)于許多內(nèi)置 HTML 元素很有用儒将。例如:
<MyComponent>hello world</MyComponent>
這是有效的 JSX,并且 MyComponent 的 props.children
值將會(huì)直接是 "hello world!"对蒲。因?yàn)?HTML 未轉(zhuǎn)義钩蚊,所以你可以像寫 HTML 一樣寫 JSX:
<div>This is valid HTML & JSX at the same time.</div>
JSX 會(huì)移除空行和開始與結(jié)尾處的空格。標(biāo)簽鄰近的新行也會(huì)被移除蹈矮,字符串常量?jī)?nèi)部的換行會(huì)被壓縮成一個(gè)空格砰逻,所以下面這些都等價(jià):
<div>Hello World</div>
<div>
Hello World
</div>
<div>
Hello
World
</div>
<div>
Hello World
</div>
jsx
可以通過子代鑲嵌嵌套更多的jsx元素,這對(duì)于鑲嵌組件非常有用泛鸟。
<MyContainer>
<MyFirstComponent />
<MySecondComponent />
</MyContainer>
其中可以混合不同類型的子元素蝠咆,同時(shí)用字符串常量和jsx子元素,這是jsx類似html的另一種形式北滥,這在jsx和html中都是有效的刚操。
<div>
Here is a list:
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
React組件也可以通過數(shù)組的形式返回多個(gè)元素
render() {
// 不需要使用額外的元素包裹數(shù)組中的元素
return [
// 不要忘記 key :)
<li key="A">First item</li>,
<li key="B">Second item</li>,
<li key="C">Third item</li>,
];
}
js表達(dá)式
可以將任何{}
包裹的js表達(dá)式作為子代傳遞,比如再芋,以下的表達(dá)式是等價(jià)的菊霜。
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
這對(duì)于渲染任意長(zhǎng)度的jsx表達(dá)式都很有用。下面將會(huì)渲染一個(gè)HTML列表济赎。
function Item(props){
return <li>{props.message}</li>
}
function TodoList(){
const todos=[
'first','second','third'
]
return(
<ul>
{todos.map(message=><Item key={message} message={message} />)}
</ul>
)
}
ReactDOM.render(
<TodoList />,document.getElementById('root')
)
js表達(dá)式可以與其他類型的子代混合使用鉴逞。這通常對(duì)于字符串模板非常有用记某。
function Hello(props) {
return <div>Hello {props.addressee}!</div>;
}
函數(shù)
在通常情況下,插入jsx中的js表達(dá)式被認(rèn)為是字符串构捡、React元素或者這些內(nèi)容的列表辙纬。然而props.children
可以向其他屬性一樣傳遞任何的數(shù)據(jù),而不僅僅是React元素叭喜。
如果你調(diào)用自定義組件,就可以使用props.children
來獲取進(jìn)行傳遞蓖谢。
// 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 渲染前將其轉(zhuǎn)換成 React 能夠理解的東西。這個(gè)用法并不常見闪幽,但當(dāng)你想擴(kuò)展 JSX 時(shí)可以使用啥辨。
布爾值、Null 和 Undefined 被忽略
false盯腌、null溉知、undefined 和 true 都是有效的子代,但它們不會(huì)直接被渲染腕够。下面的表達(dá)式是等價(jià)的:
<div />
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div>
這在根據(jù)條件來確定是否渲染React元素時(shí)非常有用级乍。以下的JSX只會(huì)在showHeader為true時(shí)渲染<Header />組件。
<div>
{showHeader && <Header />}
<Content />
</div>
相反帚湘,如果你想讓類似 false
玫荣、true
、null
或 undefined
出現(xiàn)在輸出中大诸,你必須先把它轉(zhuǎn)換成字符串 :
<div>
My JavaScript variable is {String(myVariable)}.
</div>