JSX是React引入的一個技術。讓我們深入了解一下。
- JSX簡介
- JSX入門
- 轉譯JSX
- JS in JSX
- 在JSX中使用HTML
- React中的CSS
- JSX中的表單
- JSX自動轉義
- JSX中的空格
- 在JSX中添加註釋
- 擴展屬性
- 如何在JSX中進行循環
JSX簡介
JSX是由React引入的一項技術。
儘管React在不使用JSX的情況下也可以正常工作,但它是與組件一起工作的理想技術,因此React從JSX中獲益良多。
起初,您可能會認為使用JSX就像混合HTML和JavaScript(以及CSS)。
但事實並非如此,因為使用JSX語法時,實際上是用JavaScript編寫一個組件UI的聲明語法。
您使用的不是字符串描述UI,而是使用JavaScript,這使您能夠做許多好事。
JSX入門
以下是如何定義包含字符串的h1標籤的示例:
const element = <h1>Hello, world!</h1>
它看起來像JavaScript和HTML的奇怪混合,但實際上它是完全的JavaScript。
看起來像HTML,實際上是為了定義組件以及它們在標記中的定位而添加的語法糖。
在JSX表達式中,可以非常容易地插入屬性:
const myId = 'test'
const element = <h1 id={myId}>Hello, world!</h1>
只需注意,當屬性具有連字符(-)時,它會轉換為駝峰命名法。還有兩種特殊情況:
class
變成className
for
變成htmlFor
這是因為它們是JavaScript中的保留字。
以下是一個將兩個組件包裝到div標籤中的JSX片段的示例:
<div>
<BlogPostsList />
<Sidebar />
</div>
標籤始終需要關閉,因為這更像是XML而不是HTML(如果您還記得XHTML的日子,這將是熟悉的,但此後採用了HTML5鬆散語法)。在這種情況下,使用了自閉標籤。
請注意,我將2個組件包裝到div
中。為什麼?因為**render()
函數只能返回單個節點**,所以如果您要返回2個兄弟節點,只需添加一個父節點。它可以是任何標籤,不僅僅是div
。
轉譯JSX
瀏覽器無法執行包含JSX代碼的JavaScript文件。它們必須首先轉換為常規JS。
如何轉譯?通過進行所謂的轉譯過程。
我們已經說過JSX是可選的,因為對於每一個JSX行,都有一個對應的純JavaScript替代方案可用,這就是JSX轉譯的內容。
例如,以下兩個結構是等價的:
ReactDOM.render(
React.createElement('div', { id: 'test' },
React.createElement('h1', null, 'A title'),
React.createElement('p', null, 'A paragraph')
),
document.getElementById('myapp')
)
和
ReactDOM.render(
<div id="test">
<h1>A title</h1>
<p>A paragraph</p>
</div>,
document.getElementById('myapp')
)
這個非常基本的例子只是起點,但您已經可以看到純JS語法與使用JSX相比有多麼複雜。
撰寫本文時,進行轉譯的最流行方法是使用Babel,這是在運行create-react-app
時的默認選項,因此如果您使用它,則無需擔心,一切都在幕後自動進行。
如果您不使用create-react-app
,則需要自行設置Babel。
JSX中的JS
JSX接受任何類型的JavaScript混合。
每當您需要添加一些JS時,只需將其放在大括號{}
中即可。例如,這是如何使用在其他地方定義的常量值:
const paragraph = 'A paragraph'
ReactDOM.render(
<div id="test">
<h1>A title</h1>
<p>{paragraph}</p>
</div>,
document.getElementById('myapp')
)
這是一個基本示例。大括號接受任何JS代碼:
const paragraph = 'A paragraph'
ReactDOM.render(
<table>
{rows.map((row, i) => {
return <tr>{row.text}</tr>
})}
</table>,
document.getElementById('myapp')
)
正如您所見,我們嵌套了JavaScript,該JavaScript定義在JSX內,而JSX定義在JavaScript中,您可以進行任意深度的嵌套。
JSX中的HTML
JSX在很大程度上與HTML類似,但實際上它是XML語法。
最終您要渲染HTML,所以您需要了解一些在HTML中如何定義某些內容以及如何在JSX中定義它們之間的差異。
您需要關閉所有標籤
就像在使用過XHTML的情況下一樣,您需要關閉所有標籤:不再是<br>
,而是使用自閉標籤<br />
(其他標籤也是如此)。
駝峰命名法是新的標準
在HTML中,您會找到沒有任何大小寫的屬性(例如onchange
)。在JSX中,它們被重命名為駝峰命名法:
onchange
=>onChange
onclick
=>onClick
onsubmit
=>onSubmit
class
變成className
由於JSX是JavaScript,而class
是保留詞,因此您不能寫
<p class="description">
而是需要使用
<p className="description">
相同的適用於for
,它被轉換為htmlFor
。
style屬性改變其語義
HTML中的style
屬性允許指定內聯樣式。在JSX中,它不再接受字符串,您將在React中的CSS中看到為什麼這是一個非常方便的更改。
表單
表單字段的定義和事件在JSX中進行了更改,以提供更一致性和實用性。
有關表單的更多細節,請參閱JSX中的表單。
React中的CSS
JSX提供了一種很酷的方式來定義CSS。
如果您對HTML內聯樣式有一點經驗,第一眼看起來,您會感覺自己被推到10或15年前的世界,在那裡內聯CSS是完全正常的(如今它被當作“快速修復”解決方案)。
JSX樣式與內聯CSS並不相同:首先,JSX style
屬性不像接受包含CSS屬性的字符串那樣,而僅接受一個對象。這意味著您在對象中定義屬性:
var divStyle = {
color: 'white'
}
ReactDOM.render(<div style={divStyle}>Hello World!</div>, mountNode)
或者
ReactDOM.render(<div style={{ color: 'white' }}>Hello World!</div>, mountNode)
您在JSX中編寫的CSS值與普通CSS稍有不同:
- 屬性名稱的鍵以駝峰命名法命名
- 值只是字符串
- 您使用逗號分隔每組屬性
為什麼這比純CSS / SASS / LESS更受青睞?
CSS是一個未解決的問題。自從它問世以來,圍繞它的工具數不勝數。 CSS的主要問題在於它沒有作用域,並且很容易撰寫不受限制的CSS,因此“快速修復”可能會影響不應該觸及的元素。
JSX允許組件(例如在React中定義的組件)完全封裝其樣式。
這是首選解決方案嗎?
在JSX中的內聯樣式很好,直到您需要
- 編寫媒體查詢
- 規劃動畫
- 引用偽類(例如
:hover
) - 引用偽元素(例如
::first-letter
)
總之,它們涵蓋了基本功能,但不是最終解決方案。
JSX中的表單
JSX對HTML表單工作進行了一些更改,目的是使開發人員更容易使用。
value屬性和defaultValue屬性
value
屬性始終保存字段的當前值。
defaultValue
屬性保存在創建字段時設置的默認值。
這有助於解決常規DOM交互的一些奇怪行為,例如檢查input.value
和input.getAttribute('value')
返回一個返回當前值和一個返回原始默認值的情況。
這也適用於textarea
字段,例如
<textarea>Some text</textarea>
而不是
<textarea defaultValue={'Some text'} />
對於select
字段,不使用
<select>
<option value="x" selected>
...
</option>
</select>
而使用
<select defaultValue="x">
<option value="x">...</option>
</select>
更一致的onChange事件
將函數傳遞給onChange
屬性,您可以訂閱表單字段上的事件。
它在不同的字段上以一致的方式工作,即使是radio
,select
和checkbox
輸入字段也會觸發onChange
事件。
在input
或textarea
字段中輸入字符時,onChange
事件也會觸發。
JSX自動轉義
為了減輕XSS攻擊的風險,JSX強制在表達式中自動轉義。
這意味著在字符串表達式中使用HTML實體時,可能會遇到問題。
您期望以下代碼將打印© 2020
:
<p>{'© 2020'}</p>
但它實際上打印的是© 2020
,因為字符串已轉義。
要解決此問題,您可以將實體移出表達式:
<p>© 2020</p>
或者通過使用打印HTML實體所對應的Unicode表示來使用常量:
<p>{'\u00A9 2020'}</p>
JSX中的空格
在JSX中添加空格有兩個規則:
水平空格被修剪為1個
如果在同一行上的元素之間有空格,則所有空格都被修剪為1個空格。
<p>Something becomes this</p>
變成
<p>Something becomes this</p>
垂直空格被消除
<p>
Something
becomes
this
</p>
變成
<p>Somethingbecomesthis</p>
要解決此問題,您需要明確添加空格,只需添加一個空格表達式,如下所示:
<p>
Something
{' '}becomes
{' '}this
</p>
或者通過在空格表達式中嵌入字符串來解決此問題:
<p>
Something
{' becomes '}
this
</p>
在JSX中添加註釋
您可以使用正常的JavaScript註釋在表達式中添加註釋:
<p>
{/\* a comment \*/}
{
//another comment
}
</p>
擴展屬性
在JSX中,常見的操作是為屬性分配值。
而不是手動執行,例如
<div>
<BlogPost title={data.title} date={data.date} />
</div>
您可以使用
<div>
<BlogPost {...data} />
</div>
並且data
對像的屬性將自動用作屬性,這得益於ES6的展開運算符。
如何在JSX中循環
如果您有一組元素需要進行循環以生成JSX片段,可以創建循環,然後將JSX添加到數組中:
const elements = [] //..一些數組
const items = []
for (const [index, value] of elements.entries()) {
items.push(<Element key={index} />)
}
現在在渲染JSX時,您可以將items
數組嵌入其中,方法是將其放在大括號中:
const elements = ['one', 'two', 'three'];
const items = []
for (const [index, value] of elements.entries()) {
items.push(<li key={index}>{value}</li>)
}
return (
<div>
{items}
</div>
)
您也可以直接在JSX中執行相同操作,使用map
而不是for-of循環:
const elements = ['one', 'two', 'three'];
return (
<ul>
{elements.map((value, index) => {
return <li key={index}>{value}</li>
})}
</ul>
)