iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 5
1
Modern Web

I Want To Know React系列 第 5

I Want To Know React - Render React Element

在上兩個篇章:初探 JSXJSX 語法中,我們已經了解了 JSX 的由來、功能、內部原理以及語法了。在這個篇章中,我們將要學習如何把 React element 實際 render 到畫面上。

熟悉先讓我們複習一下什麼是 React Element 吧!

React element

React element 就是 React 中,用來表示畫面上元素的物件。

我們可以使用 JSX 或是 React.createElement() 來製作 React Element:

// This is a React Element
const reactElementWithJsx = <h1>Hello React Element</h1>;

// it's equal to
const reactElementWithJs = React.createElement(
  'h1',
  null,
  'Hello React Element'
);

React element 只是 JavaScript object

需要注意的一點是,React element 不是真的畫面上的 DOM element,React element 本質上只是一種紀錄 element 資訊 ( e.g. propschildren) 的 JavaScript Object 而已。

const reactElement = <h1>Hello React Element</h1>;

console.log(reactElement);
// {
//   type: "h1",
// 	 props: {
//     children: "Hello React Element"
//   }
//   ...
// }

另外,由於 React element 只是 JavaScript Object,而非真的把資料顯示到 DOM 畫面上,因此創建 React element 的成本遠低於改變 DOM element 的成本。

接下來的問題是,我們要如何 React element 實際顯示到 DOM 上呢?

Render React elements

要把 React element render 到 DOM 上,我們就需要使用 React 的函式 ReactDOM.render

ReactDOM.render(element, container[, callback]);

此函式帶有三個參數:

  • element:代表我們要 render 的 element
  • container:代表要放 element 的 DOM parent element 中,需注意的是 container 是 DOM Element,而非 React Element
  • callback:代表 element 被 render 或被更新後要觸發的動作

接著就讓我們來看個使用範例吧!

嘗試 render 畫面

首先我們會需要在 HTML 檔案中加上一個 element 作為之後的 ReactDOM.render 第二參數:container 使用:

<div id="root"></div>

接著我們的 JSX 檔案中就可以使用 ReactDOM.renderelement render 出來了:

const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));

想看完整範例的話也可以到 React 官方提供的 CodePen 範例 去試試看。

嘗試更新畫面

另外,我們也可以使用 ReactDOM.render 來更新 DOM

<div id="root"></div>
const helloWorldElement = <h1>Hello, world</h1>;
const helloReactElement = <h1>Hello, react</h1>;

ReactDOM.render(helloWorldElement, document.getElementById('root'));
setTimeout(() => {
	ReactDOM.render(helloReactElement, document.getElementById('root'));
}, 1000);

可以看到一開始 render 出來的 Hello, world 在一秒後會被 React 更新為 Hello, react

  • ?小提醒:用 ReactDOM.render 來更新 DOM 效能較差,並不是最好的做法。這邊只是單純展示 ReactDOM.render 也可以用來更新畫面而已。

到這邊為止,我們已經學會了如何使用 React render 出 React Element 了,但對於 React render 的內部運作原理我們還需要再深入了解一下。

React render 內部原理

當我們使用 ReactDOM.render 後,React 就會幫我們把 React element render 出來,但在實際 render 到畫面之前,React 其實還幫我們做了一些事情。

簡介 React render 步驟

  1. React 在 render DOM 之前,會先為目前的 React Element(ReactDOM.render 的第一個參數)建立一個快照(snapshot),稱為 Virtual DOM

    這邊講的 snapshot 是一個 JavaScript 樹狀結構,用來仿造 DOM 結構,因此我們把它稱為 Virtual DOM

  2. 如果並非第一次觸發 render 的話,React 就會比較這次的 Virtual DOM 與上次的 Virtual DOM 的差異(Diff)

  3. 最後 React 只會把有差異的部分更新到 DOM 上

React 只會更新畫面上有改動的部分

由上一個段落中我們可以知道,React 只會把畫面上必定會變動的地方更新到 DOM 上,如此就可以降低更新 DOM 的次數。

由於更新 DOM 是一件 I/O 行為,並也會觸發更新畫面的重排(reflow)與重繪(repaint)機制,因此是個極為消耗效能的行為。而 React 把更新 DOM 的次數最小化,不會 rerender 沒有改動的 DOM element,因此就能夠避免掉非必要的效能浪費。

  • ?小提醒:偵測變更的方式不同也是 React 與 Angular、Vue 的一大差別。
    • Angular 與 Vue 主要是針對資料的角度去做差異比較,再把有差異的資料 render 到畫面上。
    • React 則是較不理會資料的變動,直接針對畫面的角度去做差異比較。

就讓我們用個小範例來驗證此概念吧!

驗證 React 只會更新畫面上有改動的部分

假設我們想做個以秒為單位的小時鐘。

首先,我們同樣會有一個 HTML element 來放置 React element 的 container 節點:

<div id="root"></div>

另外,我們有個 JSX:

// React only update the diffs
function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(element, document.getElementById('root'));
}

setInterval(tick, 1000);

可以看到此程式中,我們讓 tick 每一秒執行一次。tick 中每秒都會產生新的 React element,並執行 ReactDOM.render 來更新畫面。

接著就讓我們打開 Dev tool 看看 React 到底更新了哪些 DOM element 吧:

render-only-diff

從 Dev tool 中我們可以看到,實際上被改變的 DOM element(正在閃爍的部分)只有顯示時間的區塊而已。其他的 element: <h1>Hello, world!</h1><h2>It is </h2> 的部分都沒有被改變。

由此驗證了 React 只會更新 DOM 上有改動的部分以減少的浪費。

詳細範例也可以到 React 提供的 CodePen 範例 去看。

技巧

專案中只執行一次 ReactDOM.render()

通常一個 React app 只會呼叫一次 ReactDOM.render() 而已,並不會拿此函式來更新畫面,也因此,我們放進去的第一個參數常常會是一個代表整個專案的 React element。

在之後的章節中我們會介紹 React 其他更有效率更新 DOM 的方法。

小結

在這個章節中,我們介紹了 React element 為何並介紹了 render React element 的方式:

React element

  • React element 就是 React 中,用來表示畫面上元素的物件
  • 可用 JSX 或 React 的 createElement() 創建

Render React element 方式

  • 使用 ReactDOM.render

ReactDOM.render 內部原理

  • React 會計算畫面上會改動的部分,並只去更新 DOM 上確定會更新的 element 以減少不必要的效能浪費

ReactDOM.render 使用技巧

  • 通常整個 React 專案只會使用一次 ReactDOM.render 以提高效能

參考資料


上一篇
I Want To Know React - JSX 語法
下一篇
I Want To Know React - 初探 Component & Props
系列文
I Want To Know React30

尚未有邦友留言

立即登入留言