react
component
JSX
React組件設計入門介紹
2017/12/27 10:30:46
0
2067
React組件設計入門介紹
簡介 |
在React中元件是一切的基礎,一個畫面是由很多個元件所組合而成。透過元件化的設計,以達到可以最大化重複使用程式碼。此篇文章就來說明開發元件的基本知識與如何使用官方推薦的JSX。 |
作者 |
廖汶彬 |
React特性
- 1.基於元件(Component)化思考。
- 2.Component有狀態,而且也有生命週期。
- 3.使用JSX。
- 4.Component Prop Type防呆機制。
- 5.Virtual DOM。
- 6.一律重繪(Always Redraw)與單向資料流(Unidirectional Data Flow)。
- 7.在Javascript寫CSS(Inline Style)。
基於元件(Component)化思考
React最基本的單元為元件,每個元件也可以包含一或多個字元件。依照需求組裝成一個組合式的元件,因此具有"封裝(encapsulation)"、"關注點分離 (Separation of Concerns)"、"複用 (Reuse)"與"組合 (Compose)"等特性。以下圖為例,整個頁面被切分成多個元件,最後TodoHeader、TodoList與TodoFooter再組合成為TodoPage。 最大的差別是,過去我們習慣於將 HTML、CSS 和 JavaScript 分離,但在React開發元件時,我們會把跟元件相關的HTML、CSS 和 JavaScript封裝在一起,並以達到最大化重覆使用為目標來設計元件。
React最基本的單元為元件,每個元件也可以包含一或多個字元件。依照需求組裝成一個組合式的元件,因此具有"封裝(encapsulation)"、"關注點分離 (Separation of Concerns)"、"複用 (Reuse)"與"組合 (Compose)"等特性。以下圖為例,整個頁面被切分成多個元件,最後TodoHeader、TodoList與TodoFooter再組合成為TodoPage。 最大的差別是,過去我們習慣於將 HTML、CSS 和 JavaScript 分離,但在React開發元件時,我們會把跟元件相關的HTML、CSS 和 JavaScript封裝在一起,並以達到最大化重覆使用為目標來設計元件。
Component有狀態(state),而且也有生命週期
一般 React Component 撰寫的主要兩種方式:(請注意:注意元件開頭第一個字母都要大寫)
1.使用 ES6 的 Class(可以進行比較複雜的操作和元件生命週期的控制,相對於 stateless components 耗費資源)。
實體屬性
請注意:不要在constructor()中呼叫"setState()",直接使用初始化的方式設定值即可。
一個簡易的計數器組件程式碼,示範如何在組件內使用this.props與this.state
組件內含幾個生命周期的方法,提供開發人員在開發組件時可以覆寫該方法。
2.使用 Functional Component 寫法。(單純地 render UI,沒有內部狀態、沒有實作物件和 ref,沒有生命週期函數)
一般 React Component 撰寫的主要兩種方式:(請注意:注意元件開頭第一個字母都要大寫)
1.使用 ES6 的 Class(可以進行比較複雜的操作和元件生命週期的控制,相對於 stateless components 耗費資源)。
class MyComponent extends React.Component {
// render 是 Class based 元件唯一必須的方法(method)
render() {
return (
<div>Hello, World!</div>
);
}
}
官方有詳細的Component的介紹:
React.Component。
實體屬性
- this.props:使用組件時可由外部傳入的參數值,提供外部與組件溝通的資料。
- this.state:組件內部的狀態,可自行定義使用。
- this.props.children:特殊的props,可以取得組件內包含的所有子標籤。
請注意:不要在constructor()中呼叫"setState()",直接使用初始化的方式設定值即可。
constructor(props) {
super(props);
// 初始化狀態
this.state = {
color: props.initialColor,
name: 'Demo'
};
}
使用"setState()"來變更狀態(state)。
// 變更狀態(state),方法回傳所有狀態的屬性並將屬性"counter"改為要變更的直
this.setState((prevState, props) => {
return {...prevState, counter: prevState.counter + props.step};
});
一個簡易的計數器組件程式碼,示範如何在組件內使用this.props與this.state
組件內含幾個生命周期的方法,提供開發人員在開發組件時可以覆寫該方法。
Mounting | Updating | Unmounting | Error Handling |
---|---|---|---|
(以下方法會依序執行) constructor() componentWillMount() render() componentDidMount() |
(以下方法會依序執行) componentWillReceiveProps() shouldComponentUpdate() componentWillUpdate() render() componentDidUpdate() |
componentWillUnmount() | componentDidCatch() |
2.使用 Functional Component 寫法。(單純地 render UI,沒有內部狀態、沒有實作物件和 ref,沒有生命週期函數)
const MyComponent = () => (
<div>Hello, World!</div>
);
// 還是可以透過props傳入參數
const MyComponent = (props) => (
<div>Hello,{props.name}!</div>
);
使用JSX
使用 JSX 的好處
1. 提供更加語意化且易懂的標籤
類似 XML 的語法可以自行定義標籤且有開始和關閉,容易理解,讓一些非開發人員也更容易看懂,且能精確定義包含屬性的樹狀結構。當 Component 組成越來越複雜時,若使用 JSX 將可以讓整個結構更加直觀,可讀性較高。
2. 更加簡潔
雖然最終 JSX 會轉換成 JavaScript,但使用 JSX 可以讓程式看起來更加簡潔。
3. 結合原生 JavaScript 語法
JSX 並非一種全新的語言,而是一種語法糖(Syntatic Sugar),一種語法類似 XML 的 ECMAScript 語法擴充,所以並沒有改變 JavaScript 語意。
JSX 用法摘要
1. 標籤用法
JSX 標籤非常類似 XML ,可以直接書寫。一般 Component 命名首字大寫,HTML Tags 小寫。
解析前(特別注意在 JSX 中使用 JavaScript 表達式時使用 {} 括起,如下方範例的 text,裡面對應的是變數。若需希望放置一般文字,請加上 '')。
3. 註解
由於 JSX 最終會編譯成 JavaScript,註解也一樣使用 //(單行註解) 和 /**/(多行註解) 當做註解方式。
4. 屬性
可以透過標籤上的屬性來改變標籤外觀樣式,但要注意 class 和 for 由於為 JavaScript 保留關鍵字用法,因此在 JSX 中使用 className 和 htmlFor 替代。
在 ES6 中使用 ... 是迭代物件的意思,可以把所有物件對應的值迭代出來設定屬性,但要注意後面設定的屬性會蓋掉前面相同屬性。
在 JSX 中使用外觀樣式方法如下,第一個 {} 是 JSX 語法,第二個為 JavaScript 物件。與一般屬性值用 - 分隔不同,為駝峰式命名寫法。
在 JSX 中透過 inline 事件的綁定來監聽並處理事件,為駝峰式命名寫法。
使用 JSX 的好處
1. 提供更加語意化且易懂的標籤
類似 XML 的語法可以自行定義標籤且有開始和關閉,容易理解,讓一些非開發人員也更容易看懂,且能精確定義包含屬性的樹狀結構。當 Component 組成越來越複雜時,若使用 JSX 將可以讓整個結構更加直觀,可讀性較高。
2. 更加簡潔
雖然最終 JSX 會轉換成 JavaScript,但使用 JSX 可以讓程式看起來更加簡潔。
3. 結合原生 JavaScript 語法
JSX 並非一種全新的語言,而是一種語法糖(Syntatic Sugar),一種語法類似 XML 的 ECMAScript 語法擴充,所以並沒有改變 JavaScript 語意。
JSX 用法摘要
1. 標籤用法
JSX 標籤非常類似 XML ,可以直接書寫。一般 Component 命名首字大寫,HTML Tags 小寫。
class HelloMessage extends React.Compoent {
render() {
return (
<div>
<p>Hello React!</p>
<MessageList />
</div>
);
}
}
2. 轉換成 JavaScript
解析前(特別注意在 JSX 中使用 JavaScript 表達式時使用 {} 括起,如下方範例的 text,裡面對應的是變數。若需希望放置一般文字,請加上 '')。
var text = 'Hello React';
// 變數text,輸出為 Hello React
<h1>{text}</h1>
// 文字'text',輸出為 text
<h1>{'text'}</h1>
要特別要注意的是由於 JSX 最終會轉成 JavaScript 且每一個 JSX 節點都對應到一個 JavaScript 函數,所以在 Component 的 render 方法中只能回傳一個根節點(Root Nodes)。例如:若有多個 <div> 要 render 請在外面包一個 Component 或 <div>、<span> 元素。
3. 註解
由於 JSX 最終會編譯成 JavaScript,註解也一樣使用 //(單行註解) 和 /**/(多行註解) 當做註解方式。
4. 屬性
可以透過標籤上的屬性來改變標籤外觀樣式,但要注意 class 和 for 由於為 JavaScript 保留關鍵字用法,因此在 JSX 中使用 className 和 htmlFor 替代。
class HelloMessage extends React.Compoent {
render() {
return (
<div className="message">
<p>Hello React!</p>
</div>
);
}
}
Boolean 屬性在 JSX 中預設只有屬性名稱但沒設值為 true,反之,若是沒有屬性,則預設預設為 false。
// 有屬性名稱但沒設值,以下兩行效果一樣
<input type="button" disabled />
<input type="button" disabled={true} />
// 沒有屬性,則預設預設為 false
<input type="button" />
<input type="button" disabled={false} />
5. 擴展屬性
在 ES6 中使用 ... 是迭代物件的意思,可以把所有物件對應的值迭代出來設定屬性,但要注意後面設定的屬性會蓋掉前面相同屬性。
var props = {
style: "width:20px",
className: "main",
value: "yo",
}
<HelloMessage {...props} value="yo" />
6. 樣式使用
在 JSX 中使用外觀樣式方法如下,第一個 {} 是 JSX 語法,第二個為 JavaScript 物件。與一般屬性值用 - 分隔不同,為駝峰式命名寫法。
<HelloMessage style={{ color: '#FFFFFF', fontSize: '30px'}} />
7. 事件處理
在 JSX 中透過 inline 事件的綁定來監聽並處理事件,為駝峰式命名寫法。
<HelloMessage onClick={this.onBtn} />
Component PropType 防呆機制
除了提供 props 預設值設定(Default Prop Values)外,也提供了 Prop 的驗證(Validation)機制。
除了提供 props 預設值設定(Default Prop Values)外,也提供了 Prop 的驗證(Validation)機制。
// 注意元件開頭第一個字母都要大寫
class MyComponent extends React.Component {
render() {
return (
<div>Hello, World!</div>
);
}
}
// PropTypes 驗證,若傳入的 props type 不符合將會顯示錯誤
MyComponent.propTypes = {
todo: React.PropTypes.object,
name: React.PropTypes.string,
}
// Prop 預設值,若對應 props 沒傳入值將會使用 default 值
MyComponent.defaultProps = {
todo: {},
name: '',
}
Virtual DOM
過去Web一般是使用Javascript 或 jQuery 進行 DOM 的操作。但是更改DOM對於網頁效能的影響有著相當程度的影響。因此React設計了一個Virtual DOM的機制,讓應用程式和DOM之間透過Virtual DOM進行溝通。Virtual DOM三個重要的步驟分別是:生成Virtual DOM樹、比對Virtual DOM與實際的DOM之差異、更新畫面。
過去Web一般是使用Javascript 或 jQuery 進行 DOM 的操作。但是更改DOM對於網頁效能的影響有著相當程度的影響。因此React設計了一個Virtual DOM的機制,讓應用程式和DOM之間透過Virtual DOM進行溝通。Virtual DOM三個重要的步驟分別是:生成Virtual DOM樹、比對Virtual DOM與實際的DOM之差異、更新畫面。
一律重繪(Always Redraw)與單向資料流(Unidirectional Data Flow)
props 和 state 是影響 React Component 呈現的重要要素。其中 props 都是由父元素所傳進來,不能更改,若要更改 props 則必須由父元素進行更改。而 state 則是根據使用者互動而產生的不同狀態,主要是透過 setState() 方法進行修改。當 React 發現 props 或是 state 更新時,就會重繪整個 UI。當然你也可以使用 forceUpdate() 去強迫重繪 Component。而 React 透過整合 Flux 或 Flux-like(例如:Redux)可以更具體實現單向資料流(Unidirectional Data Flow),讓資料流的管理更為清晰。
props 和 state 是影響 React Component 呈現的重要要素。其中 props 都是由父元素所傳進來,不能更改,若要更改 props 則必須由父元素進行更改。而 state 則是根據使用者互動而產生的不同狀態,主要是透過 setState() 方法進行修改。當 React 發現 props 或是 state 更新時,就會重繪整個 UI。當然你也可以使用 forceUpdate() 去強迫重繪 Component。而 React 透過整合 Flux 或 Flux-like(例如:Redux)可以更具體實現單向資料流(Unidirectional Data Flow),讓資料流的管理更為清晰。
在Javascript寫CSS(Inline Style)
在Compoment中CSS使用Inline Style寫法,將與組件有關的資源與樣式都封裝在組件的Javascript中。需要特別注意的是樣式名稱的寫法跟一般的CSS有些許不同,以background-image為例,在inline style需改寫為backgroundImage。也就是說要去掉"-"並以camelCase的命名規則(首字的第一個字母小寫,第二個字的首字字母大寫)。React官方網站也提供了DOM Elements的說明( 連結)。
除了上述的Inline style方式,其實還有一個套件可以直接在jJavascript設定樣式,該套件名稱為" styled-components"日後有機會再來詳細介紹該套件。
套用styled-components的程式碼範例
在Compoment中CSS使用Inline Style寫法,將與組件有關的資源與樣式都封裝在組件的Javascript中。需要特別注意的是樣式名稱的寫法跟一般的CSS有些許不同,以background-image為例,在inline style需改寫為backgroundImage。也就是說要去掉"-"並以camelCase的命名規則(首字的第一個字母小寫,第二個字的首字字母大寫)。React官方網站也提供了DOM Elements的說明( 連結)。
// inline style
const divStyle = {
color: 'red',
backgroundImage: 'url(' + imgUrl + ')',
};
ReactDOM.render(<div style={divStyle}>Hello World!</div>, document.getElementById('app'));
除了上述的Inline style方式,其實還有一個套件可以直接在jJavascript設定樣式,該套件名稱為" styled-components"日後有機會再來詳細介紹該套件。
套用styled-components的程式碼範例
import React from 'react'
import styled from 'styled-components'
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`
const Wrapper = styled.section`
padding: 4em;
background: papayawhip;
`
<Wrapper>
<Title>Hello World, this is my first styled component!</Title>
</Wrapper>