Jeff的隨手筆記

學習當一個前端工程師

0%

『新手學習React』- React Basics_JSX

前言

首先我們要先複習的就是React Basics,第一篇我要來複習的是 JSX,之所以沒有選擇官方文件上的第一篇Component,是因為我認為如果我連我現在在寫的東西都不知道他是什麼的話,我要怎麼跟人家說我會呢?

什麼是JSX

先破題,JSX是React 提供了一種語法糖,能讓我們在定義 React element 的結構時有著相當類似於撰寫 HTML 語法的體驗。

在還沒看過zet助教的鐵人賽文章時,我對JSX的理解就是官方文件上的:

JSX is a syntax extension for JavaScript that lets you write HTML-like markup inside a JavaScript file.

也就是說他只是JavaScript 的語法擴展,讓我們用類似HTML的方式去編寫。

但在查找資料時,會看到很多文章都是說:『JSX 是把 HTML 寫在 JavaScript 中』。

但這跟官方文件上的有些許的不一樣,因此我去看了助教的文章才真正的瞭解他到底是什麼。

以下內容節錄JSX 根本就不是在 JavaScript 中寫 HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 以普通的呼叫 React.createElement() 來定義 React element
const reactElement = React.createElement(
'div',
{ id: 'wrapper', className: 'foo' },
React.createElement(
'ul',
{ id: 'list-01' },
// 從第三個參數開始每個參數都是子元素
React.createElement('li', { className: 'list-item' }, 'item 1'),
// 第四個參數就會是第二個子元素
React.createElement('li', { className: 'list-item' }, 'item 2'),
// 第五個參數就會是第三個子元素
React.createElement('li', { className: 'list-item' }, 'item 3'),
),
React.createElement(
'button',
{ id: 'button1' },
'I am a button'
)
);

// 以 JSX 語法來定義 React element
const reactElementWithJSX = (
<div id="wrapper" className="foo">
<ul id="list-01">
<li className="list-item">item 1</li>
<li className="list-item">item 2</li>
<li className="list-item">item 3</li>
</ul>
<button id="button1">I am a button</button>
</div>
);

上面這兩段code我們執行後會發現,使用JSX語法的code經過開發工具的自動轉換之後的React element居然會跟使用 React.createElement()的結果是一樣的,因此透過這個案例我們可以知道,寫 JSX 語法其實就是在寫 React.createElement()

所以,JSX 語法的本質完完全全就是 React.createElement() 方法的呼叫。

它長得很像 HTML 語法只是因為它被刻意設計成模仿 HTML 語法的撰寫和開發體驗,但是與 HTML 在本質上完全是不同的東西!

JSX 規則

  • Return a single root element
    在官方文件有提到,要從元件返回多個元素,請使用單個父標記將它們包裝起來To return multiple elements from a component, wrap them with a single parent tag.

    1
    2
    3
    4
    5
    6
    7
    8
    <div>
    <h1>Hedy Lamarr's Todos</h1>
    <img
    src="https://i.imgur.com/yXOvdOSs.jpg"
    alt="Hedy Lamarr"
    class="photo"
    >
    </div>

    或是可以用 Fragment(它對事物進行分組,而不會在瀏覽器 HTML 樹中留下任何痕跡。),如果Fragment沒有需要傳入任何的 props 的話,可以使用更簡潔的替代語法 — 直接以空標籤名稱
    來代表 Fragment 元素類型:

    1
    2
    3
    4
    5
    6
    7
    8
    <>
    <h1>Hedy Lamarr's Todos</h1>
    <img
    src="https://i.imgur.com/yXOvdOSs.jpg"
    alt="Hedy Lamarr"
    class="photo"
    >
    </>

    之所以要這樣主要是因為一段 JSX 其實就是呼叫一次 React.createElement(),它只會返回「一個 React element」做為結果。讓我們以樹狀結構的方式下去想,就會發現問題其實出在「樹狀資料結構只能有一個根節點」上,因此只要我們把原本想要放置在同層級的多個 React element 節點,以一個共同的父節點給包起來就可以了。

  • Close all the tags
    JSX 會要求標籤顯式關閉,就算是在 HTML 中可以只寫開標籤的元素也是一樣(例如<img>)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <>
    <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>
    </>

    因為當標籤沒有正確的閉合時,JSX transformer 就會沒有辦法解析這層的 React element 結束在哪裡,因此就會因為找不到對應的閉標籤而無法進行轉換。

  • camelCase all most of the things
    寫在JSX中的屬性(attribute)會轉換成JS 物件裡的key,在React元件裡我們有時會需要將這些屬性存取成變數,因此屬性命名方式需依照JS的變數命名規則。(例如class 必須寫成className, for必須寫成HTMLFor)
    ❗但是像是aria-*, data-*等屬性則是遵照原本HTML寫的模式

在JSX中使用JS

JSX 讓我們可以使用類似於 HTML 的語法來定義 React element,但畢竟它不像 HTML 語法一樣是純粹的文字字串,因此當想要在JSX標記內使用JavaScript表達式 就要用大括號{ }包起來,除了放回傳值的表達式也可以傳入變數、函式等等

你只能在 JSX 中以兩種方式使用大括號:

  1. 作為直接在 JSX 標籤內的文本,例如:

    1
    2
    3
    4
    5
    有效的:
    <h1>{name}'s To Do List</h1>

    無效的:
    <{tag}>Gregorio Y. Zara's To Do List</{tag}>
  2. 作為緊跟在=符號之後的屬性src={avatar}將讀取avatar變數,但如果我是成這樣src="{avatar}"則是會回傳字串{avatar}

有時候我們會在code裡面看到會使用{{ }},這個有2種可能:

  1. JSX正在傳遞一個 object

    1
    person={{ name: "Hedy Lamarr", inventions: 5 }}
  2. inline CSS styles

    1
    2
    3
    4
    5
    6
    <ul style={
    {
    backgroundColor: 'black',
    color: 'pink'
    }
    }>