在上一個篇章中介紹了何謂 React element,也講解了 render 出 React element 的方式。
在這個篇章中則要介紹要如何將寫好的 React element 做成自定義的元件:React component,並會介紹其的優點、特性與使用方式。
React Component 代表一個自定義元件的藍圖,會是 function 或 class,可以接受名為 props
的參數,並會回傳 React Element。
以下範例的 Welcome
就是一個基本 React component 的宣告與使用方式:
// function Welcome is a React Component
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// can produce React Element with JSX tag
const element = <Welcome name="Sara" />;
初學的讀者可能會分不清楚 React element 與 React component 差異。
React element 代表畫面上的元件,會是一個用來模擬 DOM element 的 JavaScript object,且會是 React render 時需要的參數。
React component 則代表一個元件的藍圖,可以想成是自定義的 HTML tag name,會是一個 function 或 class。執行後的 React component 才會產出 React element。
以上面的範例來看,Welcome
Function 是一個 React component,而 <Welcome />
元件才是 React element。
設計一個 UI 畫面時,可以將頁面看做是由小元件與區塊堆疊起來的一個大元件。一顆擁有特定樣式的 Button;一些擁有特定行為的 menu 或 form;乃至顯示特定資料的卡片區塊等都可以看做是不同大小的元件。而這就是 Atomic Design 提倡的設計思維。
以設計面來看,Atomic Design 理念可以帶來兩個好處,包括:
同樣的概念也套用到前端開發上。我們同樣可以把一個大的頁面切割為小的元件,每個元件是獨立存在且可重複利用的。因此在前端開發中,需要一個方法把這些小元件做成能夠重複利用的自定義元件。在 React 中,React component 就是用來製作自定義元件的方式。
以程式面來看,component 的切割方式能帶來一些好處:
程式的重用性
因為是自定義好的元件,因此需要時隨時都可以拿出來重複使用
提升開發效率
提高重用性後往往也能提升開發效率
封裝元件邏輯
Component 可以把自己的封裝起來,其他上層的 component 只需要正確使用介面就好,不需要接觸的內部實現細節
解藕元件間的邏輯與關注點分離
由於元件的邏輯被封裝起來,component 之間的邏輯是互不相關的,這也讓開發時做到關注點分離(Seperation Of Concerns)
Props 的意義是屬性(Properties),是由更上層 React Component 傳下來的資料。換句話說, Props 就是 React Component 的參數。
Props 會是一個任意內容的 JavaScript object,object 中的每個屬性就是一個 prop,相當於 HTML 中的 attribute,可用 JSX 傳入 React component 中。一個 component 可以接受哪些 props 則就是 component 自己定義的。
延續上面的例子,props.name
是 Welcome
中有用到的 prop,而 JSX 可以用 name="Sara"
將 prop 傳到 Welcome
中。
children
是 props 中較為特別的一個屬性,他代表 JSX element 的子 element。
只要有子層內容的 JSX element 就可以取得 children
屬性,而不是像其他的 props 一樣是用 attribute 的方式傳入。
舉例來說,如果今天我們把上面的 Welcome
component 的 prop name
修改為 children
:
// function Welcome is a React Component
function Welcome(props) {
return <h1>Hello, {props.children}</h1>;
}
// can produce React Element with JSX tag
const element = (
<Welcome>
<span>Sara</span>
</Welcome>
);
ReactDOM.render(
element,
document.getElementById('root')
);
// will output
// <h1>Hello, <span>Sara</span>
可以看到,當我們把 <Welcome>
內放入子 element <span>
時,Welcome
內拿到的 props.children
就會是 <span>Sara</span>
這個 React element。
當一個 component 需要上層傳入資料 / 狀態時,就是使用 props 的好時機。需要上層傳入資料 這句話可以分解為兩個概念:
如果出現同時符合以上兩個條件的情境就可以考慮使用 Props 了!
以下舉一些常見的範例作為使用 Props 的情境說明:
在 React 中,component 不得修改傳入的 props。對 component 來說,props 應該要是 read-only 的,這樣才能確定避免 props 隨處都可更動,導致難以追朔 props 何時被修改的問題。
這概念類似 Pure Function。一個 pure function 不會修改 input,且同樣的 input 永遠只會產生相同的 output。
Pure Function 的好處是容易預測,不會有副作用(Side Effect)。在這種 function 中,程式是相對可靠的。
對 React Component 來說也是,越 pure 或越少 side effect 的 function 就能夠越容易保證輸出的結果是正確的。
當然一個應用程式的 UI 必定會有需要改變資料與呈現的時候,這時候應該使用 state 來達成改變資料與呈現的目的。State 將在更之後的章節中介紹。
在這個段落我們將介紹 React component 宣告與使用的語法,也會提到一些該注意的事項:
React component 有兩種宣告方式:
接下來就來看一下這兩種 component 宣告方式吧!
Function component 意如其名,就是使用 function 定義 React component 的方式。
Function component 本身會是一個 function:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Function component 可以接受一個參數:
props
:為任意的 JavaScript object,為 component 的參數,可參考上面的 props 段落並可以回傳以下幾種內容:
React element
String & Number
Boolean & null
Array & Fragments
Portals
雖然 Function component 可以接受不同種的回傳值。但概念上,這些回傳值都代表著 component 自定義的 UI 內容。回傳值只要能夠被 ReactDOM.render 所接受的型別即可。
在這些不同種類的回傳值中,React element 即屬最常見的回傳內容。
我們也可以使用由 JavaScript class 定義 React component。
Class component 會是一個繼承 [React.Component](https://reactjs.org/docs/react-component.html#getsnapshotbeforeupdate)
的 class:
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Class component(React.Component
)中定義了一些函式以供開發者使用,其中 render
為 Class component 中唯一必須實作的函式,它的功能相當於 Function component,也是負責定義 component 自定義的 UI 內容。
render
不接受參數,但可以透過 this.props
取用 props 物件。
render
可回傳的內容種類與 Function component 相同:
React Element
String & Number
Boolean & null
Array & Fragments
Portals
這些回傳值也是代表 component 自定義的 UI 內容,且要是能夠被 React render 所接受的型別。
React.Component
的更多使用方式可以參照官網的 API 介紹。
?小提醒:Function component 與 Class component 有些功能上的差異,但在本篇中不會詳細介紹。
簡單來說,Function Component 與 Class Component 操作 state 的方式不同。另外,只有 Class Component 可以使用 Lifecycle 函式,Function Component 則可以使用 Hooks 達到類似的功能。
前面已經學習了如何宣告 Function component 與 Class component,接下來就來學習如何使用這些自定義的 React component 產出 React element 吧!
使用 React component 的方法與一般 JSX 的用法相同。我們可以把 React component 的 function / class 名字當作 JSX 的 tag name,並將 component 有使用到的 props 屬性以 attribute 的方式傳入 JSX 中即可產出對應的 React element:
const element = <Welcome name="Sara" />;
如果對於 JSX 還沒有很熟的讀者可以回頭閱讀 JSX 語法篇。
需要注意的是,React 規定 component 的命名必須以大寫開頭,否則會跳出警告:
function welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
ReactDOM.render(<welcome name="Sara" />, document.getElementById("root"));
// Warning: The tag <welcome> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.
到這裡為止,我們學到了何謂 React component 以及 component 的好處與語法,除此之外,也學到了 props 與其使用方式。在下一篇中將會介紹 React component 的內部運作原理與相關開發技巧。
到這裡為止,我們學到了何謂 React component 代表 React 自定義的元件,它可以帶來以下好處:
接著介紹了 props 為何:
最後則說明 React component 的兩種宣告方式以及對應的使用方法:
在下一篇中將會介紹 React component 的內部運作原理與相關開發技巧。