0%

React 概念

React 是一個很小的程式庫,沒有提供構建應用程序需要的所有功能。在 React 中,您可以在 JavaScript 代碼中編寫類似於 HTML 的代碼。 這些標籤需要進行預處理才能在瀏覽器中運行。 為此,你可能需要像 webpack 這樣的構建工具。也需要安裝像 Node.js 這樣的運行環境,以便能建構整個應用程序。

學習這樣整個開發應用程序的架構,需要時間與決心,也常常是我們學習開源應用程序的障礙。React 在剛推出的時候就容許被逐步採用,你可以按自己所需,可多可少的採用 React。不管你是想初步嘗試 React、在簡單的 HTML 網頁上加入互動性,或是實作一個使用 React 驅動的複雜應用程式。

React 不強制要求你使用特定的架構,所以你可以在不同環境中重複使用開發的 React 功能,而不需要重寫原有的程式碼。甚至可以移轉到 React Native 建立行動裝置的原生應用程序。

這裡,我們就從我們熟悉的 Oracle APEX 平台開始。我們可以利用 APEX 伺服器與前端的開發工具加入 React 元件,增進 APEX application 的互動性,也可透過 API 攫取不同來源的網路資源,加強資料的整合性。我們不需要安裝 Node.js 與 webpack。

未來如果需要,這些在 APEX 中開發的 React 元件,也可以很快速地應用在其他架構。

但開始學習 React 之前,你仍必須有堅實的 JavaScript 技術。React 在最近幾年快速的發展,在最近的 2019 年 React 16.8 我們看到了 Hooks 的發布,這是一種在組件(components)之間添加和共享狀態(state)邏輯的新方法,它讓你不必寫 class 就能使用 state 以及其他 React 的功能,讓程式碼更加簡潔。這會大量的使用 JavaScript ES6 的最新語法。

你如果在網路上看到使用 class 的 React 組件,請不要再用。class component 將來可能會被棄用。Function components 與 Hooks 是 React 的未來。

身為一個專業的軟體工程師,不管你伺服端使用何種架構、何種資料庫,你還是都得精於 JavaScript。JavaScript 是目前軟體工程師最重要的技術。

APEX 平台

這裡使用的 APEX 版本是 5.1.4。如果你使用的環境低於 5.1.4,建議您盡快升級。它除了有較好的使用者介面,伺服端也提供 APEX_JSON Package 支援 JSON。JSON 是目前資料交換最重要的格式,你也須花點時間了解它。

要在 APEX 中能夠運作,我們必須 import 三個 JavaScript 程式庫。你可以將這三個程式庫加入 APEX Page Properties 的 JavaScript > File URLs 中。

我們會在開發 React 時用到 JavaScript ES6 與 React JSX 語法,並不是所有的瀏覽器都支援這些語法,Babel 就是負責這些預處理,將這些語法事先轉譯成瀏覽器看得懂的語法,這稱為 compiling。

React 如何運作的

使用 React 時,會用 JSX 創建應用程序。JSX 是基於標籤(tag-based)的 JavaScirpt 語法,看起來很像 HTML。使用 React 必須深入探討 JSX。 為了真正理解 React,我們就從其最原子的單元:React 元素(React elements)開始。但我們先不使用 JSX 語法,而先用 React.createElement 來探討 React 元素。

React Elements

我們將了解 React 元素,及如何與其他元素組成自定義的 React 組件(React components),從而了解 React 組件。

瀏覽器 DOM 由 DOM 元素(DOM elements)組成。 同樣,React DOM 由 React 元素組成。 DOM 元素和 React 元素看起來相同,但實際上卻完全不同。 React 元素是對實際 DOM 元素的外觀的描述。 換句話說,React 元素是有關如何創建瀏覽器 DOM 的指令。

我們可以使用 React.createElement 創建一個 React 元素來代表 h1。

在 APEX Page 建立一個 Region,在 Region Properties 的 Source > Text 加入程式碼:

Region Source Text
1
2
3
4
5
6
7
<div id="react-root"></div>

<script type="text/babel">
const hello = React.createElement("h1", { id: "hello" }, "Hello Scott!");

ReactDOM.render(hello, document.getElementById("react-root"));
</script>
  • 第 3 行的 script 標籤的 type 是 text/babel,Babel 將在運行客戶端之前在客戶端上事先編譯代碼。
  • 第 4 行使用 React.createElement 創建一個 React 元素
    • 第一個參數定義我們要創建的元素的類型。 在這裡,我們要創建一個 h1 元素。
    • 第二個參數表示元素的屬性(properties)。 創建的 h1 當前具有 id 為 hello 的屬性 。
    • 第三個參數表示元素的子元素:在開始和結束標記之間插入的任何節點,在這裡,僅是一些文本字串 “Hello Scott!”。
  • 第 6 行 ReactDOM.render 會將創建的 React 元素渲染(rendering)為實際的 DOM 元素。並掛載到實際的 DOM 目標節點 react-root。

渲染後實際的 DOM 元素如下:

1
<h1 id="hello">Hello Scott!</h1>

React 元素只是一個 JavaScript 描述,告訴 React 如何構造 DOM 元素。如果將它 log 到 Chrome 開發環境的 Console,則它會像:

1
2
3
4
5
6
7
8
9
{
$$typeof: Symbol(react.element),
key: null,
props: {id: "hello", children: "Hello Scott!"},
ref: null,
type: "h1",
_owner: null,
_store: {validated: false}
}

所看到的這些字段(fields) 對 React 都很重要,先讓我們仔細看看 type 和 props 字段。

React 元素的 type 屬性告訴 React 創建哪種類型的 HTML 或 SVG 元素。 props 屬性表示構造 DOM 元素所需的數據和子元素。 children,用於將其他嵌套元素顯示為文本。

ReactDOM

創建 React 元素後,我們希望在瀏覽器中看到它。 ReactDOM 包含了在瀏覽器中呈現 React 元素所需的工具。 在上端程式碼的第 6 行 ReactDOM.render 就是我們所需要的。 在 React 16 以後的版本 render 也可以接受陣列,這會使陣列中的元素都成為同級元素(siblings)。

Children

React 使用 props.children 渲染子元素。 我們也可以將其他 React 元素渲染為子元素,從而創建樹狀元素。

1
2
3
4
5
6
7
React.createElement(
"ul",
null,
React.createElement("li", null, "Hello Scott"),
React.createElement("li", null, "Hello Emily"),
React.createElement("li", null, "Hello Amanda")
);

渲染後實際的 DOM 元素如下:

1
2
3
4
5
<ul>
<li>Hello Scott</li>
<li>Hello Emily</li>
<li>Hello Amanda</li>
</ul>

我們可以改用陣列的 map 映射創建列表項:

1
2
3
4
5
6
7
8
9
10
11
12
13
const userData = [
"Scott",
"Emily",
"Amanda"
];

const hello = React.createElement(
"ul",
null,
userData.map((user, i) =>
React.createElement("li", { key: i }, `Hello ${user}`)
)
);

當我們透過迭代陣列來構建子元素列表時,React 需要每個元素都有一個 key 屬性。 React 使用 key 屬性來更有效率地更新 DOM。

React Components

無論其大小,內容或使用何種技術創建,使用者介面都是由部件(parts)組成的。 按鈕,列表,標題等等。所有這些部件放在一起構成一個使用者介面。有些介面所需的部件都相同,可以重複使用。

在 React 中,我們將每個部件描述為一個組件(component)。組件使我們可以重用相同的結構,然後可以使用不同的數據集填充這些結構。

我們將通過編寫函式來創建組件。該函式將返回使用者介面的可重用部件,也就是 React 組件。

讓我們創建一個返回無序列表的函式。我們將這函式取名為 UsersList。

UsersList
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function UsersList() {
return React.createElement(
"ul",
null,
React.createElement("li", null, "Hello Scott"),
React.createElement("li", null, "Hello Emily"),
React.createElement("li", null, "Hello Amanda")
);
}

ReactDOM.render(
React.createElement(UsersList, null, null),
document.getElementById("react-root")
);

這個 UsersList 函式返回的就是一個組件,該組件的名稱就稱為 UsersList,該函數輸出如下所示的元素:

1
2
3
4
5
6
7
<UsersList>
<ul>
<li>Hello Scott</li>
<li>Hello Emily</li>
<li>Hello Amanda</li>
</ul>
</UsersList>

這很酷,但是我們目前將數據硬編碼到組件中。如果我們可以構建一個組件,然後將數據作為屬性傳遞給該組件,然後該組件可以動態呈現數據,這將會更棒。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const userData = [
"Scott",
"Emily",
"Amanda"
];

function UsersList(props) {
return React.createElement(
"ul",
null,
props.users.map((user, i) =>
React.createElement("li", { key: i }, `Hello ${user}`)
)
);
}

ReactDOM.render(
React.createElement(UsersList, { users: userData }, null),
document.getElementById("react-root")
);
  • 第 7 行在組件函式加一個參數,以便在調用時可以動態的傳入資料。這個參數習慣上都命名為 props,表示這是組件的屬性(properties)。
  • 第 18 行透過 React.createElement
    • 第一個參數調用 UsersList 函式,產生一個 UsersList 組件。
    • 第二個參數表示組件的屬性(properties)。 這裡有一個值是 userData 的 users 屬性。所有在這裡定義的屬性被包裝在一個物件中,做為 UsersList 函式的引數。這就是第 7 行 UsersList 函式的參數 props。第 11 行可從 props.users 取得 userData 的資料。

讓我們看一下DOM。

1
2
3
4
5
6
7
<UsersList users="[...]">
<ul>
<li key="0">Hello Scott</li>
<li key="1">Hello Emily</li>
<li key="2">Hello Amanda</li>
</ul>
</UsersList>

注意第 1 行的 users 屬性。

我們還可以通過解構賦值(Destructuring assignment) props 的數據來稍微簡潔代碼,users 預設值為 [ ],可以防止調用時沒有傳入 users 屬性:

1
2
3
4
5
6
7
8
9
function UsersList({ users = [] }) {
return React.createElement(
"ul",
null,
users.map((user, i) =>
React.createElement("li", { key: i }, `Hello ${user}`)
)
);
}

改用箭頭函式運算式(arrow function expression):

1
2
3
4
5
6
7
8
9
const UsersList = ({ users = [] }) => (
React.createElement(
"ul",
null,
users.map((user, i) =>
React.createElement("li", { key: i }, `Hello ${user}`)
)
)
);

使用 React.createElement 函式是了解 React 如何工作的好方法,但是作為 React 開發人員,這不是我們要做的。為了有效地使用 React,我們還需要做一件事:JSX。React with JSX