用 JSX 撰寫 Markup
JSX 是一種 JavaScript 的擴充語法,讓你能夠在 JavaScript 檔案中編寫類似 HTML 的 markup。雖然也可以使用其他的方式來編寫 component,但大多數的 React 開發者偏好於使用簡明的 JSX,並在大部分代碼庫中使用它。
You will learn
- 為什麼 React 耦合 markup 與 render 邏輯
- JSX 與 HTML 有什麼區別
- 如何透過 JSX 展示資訊
JSX:將 markup 引入 JavaScript
網頁是建構於 HTML、CSS 與 JavaScript 之上的。多年以來,網頁開發者將內容存放在 HTML,在 CSS 中設計樣式,然後將邏輯存放於 JavaScript 中-通常是在不同的文件中!頁面內容透過標記式語言存放於 HTML 檔案中,而邏輯則單獨存放在 JavaScript 檔案中:
但隨著網頁的交互性越來越強,邏輯增加了對內容的決定性。JavaScript 負責了 HTML 的內容! 這也是為什麼在 React 中,render 邏輯與 markup 存在於同一個地方-component。
將一個按鈕的 render 邏輯與 markup 放在一起,可以確保它們在每次編輯時都能互相保持同步。反之,彼此無關的細節則是互相隔離的,像是按鈕的 markup 與側邊欄的 markup。這樣可以使修改其中一方時更加安全。
每個 React component 都是一個 JavaScript 函式,裡面可能會包含一些用於瀏覽器 render 的 markup。 React component 使用名為 JSX 的擴充語法來表示 markup。JSX 看起來像是 HTML,但它的語法較為嚴格,並且可以展示動態資訊。了解這些區別的最好方式就是將一些 HTML markup 轉換為 JSX markup。
將 HTML 轉換為 JSX
假設你有一些 (完全有效的) HTML:
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
<li>Invent new traffic lights
<li>Rehearse a movie scene
<li>Improve the spectrum technology
</ul>
然後你想要將它放入你的 component:
export default function TodoList() {
return (
// ???
)
}
如果像下方這樣直接複製貼上是沒有辦法運作的:
export default function TodoList() { return ( // This doesn't quite work! <h1>Hedy Lamarr's Todos</h1> <img src="https://i.imgur.com/yXOvdOSs.jpg" alt="Hedy Lamarr" class="photo" > <ul> <li>Invent new traffic lights <li>Rehearse a movie scene <li>Improve the spectrum technology </ul>
這是因為 JSX 比語法 HTML 更加嚴格,且有更多的規則!上方的錯誤訊息可以幫助你修復 markup,或是你也可以參考下方的指引。
JSX 的規則
1. 回傳單一根元素
如果想要在一個 component 中回傳多個元素,請將它們包裹進父標籤。
例如,你可以使用一個 <div>
標籤:
<div>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
...
</ul>
</div>
如果你不想要在你的 markup 放入多餘的 <div>
標籤,可以改為使用 <>
與 </>
:
<>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
...
</ul>
</>
這個空標籤稱為 Fragment,Fragment 允許你將元素集合在一起,且不會在 HTML 中產生額外節點。
Deep Dive
JSX 看起來與 HTML 非常相似,但它實際上是 JavaScript 物件。你不能在沒有使用 array 包裹它們的情況下,在一個函式裡回傳兩個物件。這解釋了為什麼你不能在沒有使用其他標籤或 Fragment 包裹的情況下回傳兩個 JSX 標籤。
2. 閉合所有標籤
JSX 標籤需要明確地閉合:如果是自閉標籤,像是 <img>
,則需要改為 <img />
,而像 <li>oranges
這樣只有開始標籤的元素則需改為 <li>oranges</li>
。
海蒂・拉瑪的照片與列表項目更改後如下:
<>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
/>
<ul>
<li>Invent new traffic lights</li>
<li>Rehearse a movie scene</li>
<li>Improve the spectrum technology</li>
</ul>
</>
3. 全部 大部分使用駝峰式命名!
JSX 最終會被轉化為 JavaScript,編寫在 JSX 中的屬性會變成 JavaScript 物件中的 key。在你的 component 中,你會經常需要使用變數的方式讀取這些屬性。但是 JavaScript 對變數命名有限制。例如,它們的名字不能包含連字號,或者是使用像是 class
這樣的保留字。
這就為什麼在 React 中,許多 HTML 與 SVG 屬性都使用駝峰式命名法。例如,將 stroke-width
改為 strokeWidth
。由於 class
為保留字,因此在 React 中需要改為使用 className
來替代。 這也是依據 相應的 DOM 屬性 命名:
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
className="photo"
/>
你可以 在 DOM component props 列表找到所有屬性,如果你在過程中發生了錯誤,別擔心-React 會在 瀏覽器控制台 打印出可能的更正信息。
專業提醒:使用 JSX 轉換器
轉換所有現有的 markup 屬性是一件繁瑣的事情!我們建議使用 轉換器 來將現有 HTML 與 SVG 轉換為 JSX。轉換器在實務上是非常實用的,但我們仍有必要去理解轉換過程,這樣你就可以編寫自己的 JSX 了。
以下為最終結果:
export default function TodoList() { return ( <> <h1>Hedy Lamarr's Todos</h1> <img src="https://i.imgur.com/yXOvdOSs.jpg" alt="Hedy Lamarr" className="photo" /> <ul> <li>Invent new traffic lights</li> <li>Rehearse a movie scene</li> <li>Improve the spectrum technology</li> </ul> </> ); }
Recap
現在,你知道為什麼我們需要 JSX,並且知道如何在 component 中使用它:
- 由於 render 邏輯與 markup 關係緊閉,所以 React 將它們存放在同一個 component 中。
- JSX 與 HTML 非常相似,但它們有些許不同,如果你需要轉換它們,你可以使用 轉換器。
- 錯誤提示訊息通常能指引你往正確的方向修復 markup。
Challenge 1 of 1: 將 HTML 轉換為 JSX
下方的 HTML 是直接被複製到 component 中的,並非有效的 JSX。請試著修復它:
export default function Bio() { return ( <div class="intro"> <h1>Welcome to my website!</h1> </div> <p class="summary"> You can find my thoughts here. <br><br> <b>And <i>pictures</b></i> of scientists! </p> ); }
手動修復或是使用轉換器都可以的,一切取決於你!