iT邦幫忙

2022 iThome 鐵人賽

DAY 5
1
Modern Web

一次打破 React 常見的學習門檻與觀念誤解系列 第 5

[Day 05] 建構一切 UI 的最基本單位 — React element

  • 分享至 

  • xImage
  •  

React 採用了上一篇文章中所介紹的的 Virtual DOM 概念來實作抽象層,以產生並管理瀏覽器畫面中的真實 DOM。而在 React 中的每一個 Virtual DOM element 稱之為「 React element」,作為這個抽象層中的最小組成單位。

React element 是一種普通的 JavaScript 物件資料,用來描述對應於「真實 DOM」的節點資料與結構。你可以透過 React 提供的 createElement() 方法來建立一個 React element,例如:

import React from "react";

const buttonReactElement = React.createElement(
  'button',           // 元素類型
  { id: 'button1' },  // 屬性
  'I am a button'     // 子元素
);

createElement() 的第一個參數為元素類型,第二個參數為屬性,而第三個參數則為子元素。

產生出來的 React element 會是一個普通的 JavaScript 物件,嘗試將其 console.log 印出來之後你會發現它長得大概像這樣:

// buttonReactElement
{
  type: 'button',
  props: { id: 'button1', children: 'I am a button' },
	key: null,
  ref: null,
  $$typeof: Symbol('react.element'),
};

看起來確實是一個再普通不過的 JavaScript 物件資料,然而將這個 React element 交由 React 進行轉換處理之後,就可以自動產生對應的實際的瀏覽器 DOM 畫面結果:
Untitled

此時的真實 DOM Tree 中,就可以找到這個由 React 代你自動產生的實際 DOM element:

const buttonDomElement = document.getElementById('button1');

在上面這個範例中:

  • buttonReactElement
    • 是一個 React element,在交給 React 進行渲染轉換之前就只是個 JavaScript 物件。意義上就是一個 Virtual DOM element,用來讓開發者描述並定義,希望到時候產生的真實 DOM 會長成什麼樣子
  • buttonDomElement
    • 是一個真實的 DOM 節點,由 React 基於接收到的 React element 內容來幫你自動產生的對應結果

當然,與真實的 DOM 一樣,React element 也可以是巢狀的樹狀結構,你可以將一個 React element 的子元素指定成另一個或多個 React element。

如果子元素不只一個的話,可以繼續在 createElement() 的第四、第五、第六......第 N 個參數以此類推往下填,React 會依序將它們視作接續的子元素:

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'
  )
);

會產生對應的瀏覽器 DOM 畫面結果:
Imgur

如上所見,我們可以透過定義 React element 的內容,來間接控制實際上畫面最後產生的 DOM 結構,兩者之間有著顯而易見的完整對應。

但需要注意的是,React element 一旦被建立之後就是不可被事後修改的。為什麼呢?

如同我們在前文有提到過的,在 React 中的 Virtual DOM element 就是指 React element。而為了最佳化 DOM 操作的效能,當畫面即將有更新需求時,我們需要將舊有的 Virtual DOM Tree 結構與新畫面版本的 Virtual DOM Tree 進行比較,才能知道哪些地方是真正需要進行 DOM 更新的。因此如果之前已經建立的舊 React element 會被事後修改或覆蓋的話,不就沒有可靠的歷史依據來跟新的 React element 進行比較了嗎?

因此,React element 從概念上來說就像是在表達「某一個歷史時刻當時的畫面 UI」。所以當我們想要重新描述一個新畫面的結構時,就必須產生一組全新的 React element 來提供給 React,而永遠不會去修改舊有的 React element,以保證這個與歷史結構的比較機制能夠成立並維持。

建議參考資源:

補充說明:React element 中與 DOM 的屬性對應和差異

你可能會發現有些 React element 的屬性名稱和格式,與對應的真實 DOM 有些許的不同。這裡列出一些最常見且常用的差異之處:

  • 所有的 DOM property 和 attribute(包括 event handler)都會改以 camelCase 命名
    • 例如:onclickonClicktabindextabIndex ...等等
    • aria-*和 data-* attribute 則是例外,需要保持全部小寫。舉例來說,aria-label 保持原樣即可
  • 有一些涉及到 JavaScript 內建保留字的屬性會稍微改名以避免意外情況,例如:
    • classclassName
    • <label> 會有的 for 屬性 ⇒ htmlFor
  • 指定 inline styles 的 style 屬性的內容格式不同:
    • 在 React element 中, style 是以物件的格式指定的,而非像撰寫 HTML Tag 時那樣以字串指定,且其中的 CSS properties 名稱都會改以 camelCase 來表示。

    • 舉例來說:

      原本在 HTML 中的 style="font-size: 14px; color: red;",在 React element 中則是以 { style: { fontSize: '14px', color: 'red' } } 的形式表示

完整詳細的差異表可以參考官方文件:
https://reactjs.org/docs/dom-elements.html#differences-in-attributes


2024/2 更新 - 實體書平裝版本預購

在經過快要一年的努力後,本系列文的實體書版本推出了~其中新增並補充了許多鐵人賽版本中沒有的脈絡與細節,並以全彩印刷拉滿視覺上的閱讀體驗,現正熱銷中!有興趣的話歡迎參考看看,也歡迎分享給其他有接觸前端的朋友們,非常感謝大家~

《React 思維進化:一次打破常見的觀念誤解,躍升專業前端開發者》

目前首刷的軟精裝版本各大通路已經幾乎都銷售一空,接下來會再刷推出新的平裝版本:

天瓏(平裝版預購):
https://www.tenlong.com.tw/products/9786263337695

博客來(平裝版):
https://www.books.com.tw/products/0010982322

momo(平裝版):
https://www.momoshop.com.tw/goods/GoodsDetail.jsp?i_code=12528845


上一篇
[Day 04] DOM 與 Virtual DOM
下一篇
[Day 06] Render React elements
系列文
一次打破 React 常見的學習門檻與觀念誤解30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言