iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 6
0
自我挑戰組

React 30 天學習歷程系列 第 6

【Day 6】用 JSX 來寫 HTML 標籤

JSX 簡介

JSX 是 react 打包的一種 JS 標籤語法,它其實不是字串或 HTML,不過 JSX 是基於 HTML 的特性使用 JS 開發出來的,因此擁有 HTML 大部分的特性,可以當作 HTML 使用,React 中我們使用 JSX 來寫 HTML 的標籤。

其實 JSX 是為 React.createElement 函式提供的語法糖,React.createElement 主要是用於生成 React Elements,這是一種 Virtual DOM ,Virtual DOM 經過比較和計算後再渲染成原生 DOM。使用 Virtual DOM 是因為 React 希望當資料有更新時,頁面可以自動重新渲染,但是渲染整個頁面相對花費的時間及資源都比較多,因此才需要 Virtual DOM 的幫助,在資料更新時,先重新繪製 Virtual DOM 與 Real DOM 做比對,有變動的地方才去做更新。

JSX 和 HTML 的差異

  • JSX 和 HTML 是兩種不同的標籤語法,但幾乎有相同的特性以及寫法(標籤、標籤屬性及事件)。
  • JSX 是 JS 語法的延伸,HTML 則是原生的標籤語法。
  • JSX 可以使用 JS 表達式,但 HTML 不行。
  • JSX 可以預防 xss 漏洞,但 HTML 不行。
  • JSX 事件和標籤屬性需要使用駝峰式命名,但 HTML 不需要。
  • JSX 會先被轉換成 React DOM,再轉換成原生 DOM,而 HTML 是直接生成原生 DOM。
  • JSX 和 HTML 部分屬性有差異,比方說 HTML 的 class 對應 className

命名方式差異

在 JSX 中,所有的事件名和屬性名都,只要是由超過兩個單字以上組成都需要使用駝峰式命名,除了 aria-*data-*屬性名,例子如下:

    <input type="text" minLength="10" />

事件名例子如下:

// 在 html 中是 onclick
    <button onClick={() => alert('已經送出')}>送出</button>

使用 inline style 時,也有部分 CSS 屬性需要駝峰命名,因為 style 在 JSX 中接受的實際上是物件,因此屬性名稱是多於兩個以上的單字,通常都要駝峰命名

<input type="text" style={{backgroundColor: 'red', fontSize: 15}} />

屬性差異

在 JSX 中,部分屬性名和 HTML 不同。

  1. class 改為 className
<input type="text" className="colorClass" />
  1. defaultValue: 在 JSX 中 input 除了使用 value 外,還可以使用 defaultValue 來設置第一次裝載時候的默認值。
<input type="text" value="固定值" />
<input type="text" defaultValue="初始默認值" />
  1. checkeddefaultChecked : checked 可以用於判斷 checkboxradio 是否被選中,defaultChecked 可以設置第一次裝載時候,默認選中的值。
<input type="radio" checked="checked" />白色
<input type="radio" defaultChecked={true} />紅色
  1. innerHTMLdangerouslySetInnerHTML : dangerouslySetInnerHTML 相當於 HTML 的 innerHTML,React 中沒有 innerHTML 這個屬性,所以使用 dangerouslySetInnerHTML 來插入 HTML 字串。dangerouslySetInnerHTML 的值必須是一個物件,物件中使用 __html 來接受字串,如下
const htmlStr = '<h1>title</h1>';

<App>
    <div dangerouslySetInnerHTML={{__html: htmlStr}}></div>
</App>

JSX 使用方式

基本上 JSX 的使用方式,就是直接在裡面寫 HTML 標籤即可,如下:

const App = () => {
    return <div>
    <span>JSX</span>
    </div>
}

JSX 中使用 JS 表達式

JSX 中可以使用 {} 來輸入 JS 表達式,另外 JSX 也可以作為表達式賦給變數使用

const Profile = (props) => {
    const {name} = props;
    const nameTitle = <h1>Profile</h1>
    return <div>
    { nameTitle }
    <span>My name is { name }</span>
    </div>
}

傳遞參數時,如果是變數、數值或布林,也需要使用 {} 來傳遞,如果是字串則不用

const Profile = (props) => {
    const {name} = props;
    const nameTitle = <h1>Profile</h1>
    return <div>
    { nameTitle }
    <span>My name is { name }</span>
    <ProfileData
        age={31}
        gender="male"
    />
    </div>
}

// 在子組件輸出
const ProfileData = ({age, gender}) => {
    return <div>
        <p>age: {age}</p>
        <p>gender: {gender}</p>
    </div>
}

在 JSX 中使用事件

JSX 中,可以直接在事件後面用表達式,或是將函式賦在變數上呼叫,如下面的範例,將一個函式賦在 sendEvent 上,之後在元件中呼叫 sendEvent 來調用函式:

const Profile = (props) => {
    const sendEvent = () => {
        console.log('送出成功')
    }
    return <div>
        <button onClick={sendEvent}></button>
        <button onClick={() => console.log('送出成功')}></button>
    </div>
}

在 JSX 中加載圖片

JSX 中加載圖片有兩種方式,一種是用 require,一種是用 import,如果是用 import,必須先賦給一個變數,再去調用變數。

import Img from './test.png'
const Profile = (props) => {
    return <div>
        <img src={require("./test.png")} />
        <img src={Img} />
    </div>
}

JSX 中的條件判斷

JSX 中不能直接使用 if else 判斷,但可以使用三元運算子判斷,例如下面的範例,用三元運算子判斷是否 loading

const App = ({loading}) => {
    return <div>
        {loading ? <div>下載中...</div> : null}
    </div>
}

也可以在三元運算子中再使用三元運算子判斷,如下

const App = ({loading, name}) => {
    return <div>
        {
            loading ?
            name ? <span>{name}</span> : null
            : null
        }
    </div>
}

另外,也可以使用 && 來做判斷,如下面範例,當 loadingtrue 的時候,後面的 <div>下載中...</div> 也會一起顯示

const App = ({loading}) => {
    return <div>
        {loading && <div>下載中...</div>}
    </div>
}

也可以在 JSX 之前使用 if 判斷,把判斷的結果交給變數,輸出到 JSX 中,如下

const App = ({user}) => {
    let isLogin = flase;
    if (user && user.id) isLogin = true;
    return <div>
        {isLogin ? <div>你已經登入</div> : <div>尚未登入</div>}
    </div>
}

但上面這種作法,一般比較少人使用,通常都是將判斷直接寫在 JSX 中。

在 JSX 中渲染多個標籤(元件)或陣列資料

JSX 中渲染多個標籤或元件不難,但是會有許多種情況,這邊就讓我們一個個了解。

用 Fragment 包裹返回列表

React 組件可以返回封閉的標籤或字串,但不支持直接返回列表,如下面的情況,就是錯誤例子

//錯誤範例
const App = () => {
    return (
        <li></li>
        <li></li>
        <li></li>
    )
}

這種情況下,我們必須用 Fragment 來包住列表。Fragment 是 jsx 用來包住列表或多個標籤用的,其本身不會生成額外標籤,如下

import React, { Fragment } from 'react';
const App = () => {
    return <Fragment>
        <li></li>
        <li></li>
        <li></li>
    </Fragment>
}

使用 <></> 包住列表

<></> 其實是 Fragment 的簡寫,不過有部分工具可能不支援這種寫法

import React from 'react';
const App = () => {
    return <>
        <li></li>
        <li></li>
        <li></li>
    </>
}

用 map 渲染陣列資料

JSX 中,陣列資料的渲染,通常都是使用 map,另外要注意的是,React 中規定,渲染陣列資料時,每一筆資料都必須有 key 屬性,key 能幫助 React 確認哪一筆資料被修改或移除,每一筆 key 都是獨有的,不能重複。

const App = (props) => {
    const { lists = [] } = props;
    return (
        <div>
            {
                lists.map(item => 
                    <div key={item.id}>
                        <div>{item.name}</div>
                        <div>{item.age}</div>
                        <div>{item.gender}</div>
                    </div>
                )
            }
        </div>
    )
}

小結

JSX 常見的用法雖然原本就知道,但我並不是全部都清楚程式碼實際上的運作方式,因此特地在這一篇中整理了一次。下一篇開始會整理一些 React 中常見,但我比較不熟悉的 CSS 處理方案。


上一篇
【Day 5】React 中常用的一些 ES6 語法 (三)
下一篇
【Day 7】CSS 處理方案(一)
系列文
React 30 天學習歷程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言