react component JSX

React組件設計入門介紹

廖汶彬 2017/12/27 10:30:46
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封裝在一起,並以達到最大化重覆使用為目標來設計元件。


Component有狀態(state),而且也有生命週期

一般 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,可以取得組件內包含的所有子標籤。
狀態(state)可在 constructor()進行狀態的初始化。
請注意:不要在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 小寫。
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)機制。
//  注意元件開頭第一個字母都要大寫
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之差異、更新畫面。


一律重繪(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),讓資料流的管理更為清晰。


在Javascript寫CSS(Inline Style)

在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>



廖汶彬