React 本質
- React本質是個狀態機(state machine)
- React只關注兩件事:(1)更新DOM; (2)回應事件。
- React是MVC中的V(View),意即React只處理「視圖」。
React 優點
- JS 元素的狀態變更、重新渲染頁面會非常緩慢,意即 native DOM的讀取和更新是非常消耗性能的
- React 有自己的 Virtual DOM,並且利用Diff算法計算Virtual DOM 和 native DOM的差異,其優點在於:(1)只更新必要的部分; (2)最小化回流(reflow)。
Component
書中範例是用Class componenet寫法
- 自訂元件
- 動態值:大括號
- 子節點
自訂元件
var Divider = React.createClass({
render: function(){
return (
<div className="divider">
<h2>Quetions</h2><hr/>
</div>
);
}
})
動態值
JSX會渲染 {...}
裡的動態值,書中介紹以下常用寫法:
寫法1. 變數
簡單的值或數字可用變數
var text='Questions';
<h2>{text}</h2> // <h2>Questions</h2>
寫法2. 函式
複雜邏輯可用函式
function dateToString(d){
return [
d.getFullYear(),
d.getMonth()+1,
d.getDate()
].join('-');
};
<h2>{dateToString(new Date())}</h2> // <h2>2014-10-18</h2>
寫法3. 陣列
React會自動把陣列每項元素渲染成一個節點
var text=['hello', 'world'];
<h2>{text}</h2> // <h2>helloworld</h2>
子節點
React用一個特殊的元件屬性陣列 - this.prop.children
來捕捉標籤中包含的所有子節點:
// JSX
var Divider = React.createClass({
render: function(){
return (
<div className="divider">
<h2>{this.props.children}</h2><hr/>
</div>
);
}
});
// HTML
<Divider>Questions</Divider>
JSX
JavaScript XML 是一種用於React元件的標記語法,每個JSX標記映射到一個JS函式,雖然與HTML相似,卻有與HTML不同的以下特性:
- HTML屬性命名
- CSS命名
- 屬性:可用動態變數或函式設定; 選擇語句
- Non-DOM 特殊屬性
- 事件
- 註解
HTML屬性命名
- class → className
- for → htmlFor:
<label htmlFor="for-text" ... />
CSS命名
都是camelCase方式命名,不可用原來的-
。
var styles = {
borderColor: "#999",
borderThickness: "1px"
};
React.renderComponent(<div style={styles}>...</div>, node);
JSX屬性
<div> id="some-id" class="'some-class-name'">...</div>
寫法1. 變數
var surveyQuestionId = this.props.id;
var classes = 'some-class-name';
// ...
<div id={surveyQuestionId} className={classes}></div>
寫法2. 取得函式結果
<div id={this.getSurveyId()}>...</div>
選擇語句
<div className={if(isComplete) { 'is-complete' } } }>...</div>
是不好的表達方式,可以改用以下替代方案:
- 三元邏輯
- 變數
- 函式
&&
operator
三元邏輯
render: function(){
return <div className={this.state.isComplete ? 'is-complete' : '';}>...</div>;
}
變數
三元邏輯有時會難以閱讀,這時可以替三元邏輯的語法新增為一個變數。
getIsComplete: function(){
return this.state.isComplete ? 'is-complete' : '';
},
render: function(){
var isComplete = this.getIsComplete(); // 先給變數
return <div className={isComplete}>...</div>
}
函式
因為上述範例是用函式取得三元邏輯的結果,也能省略使用變數,直接呼叫函式。
getIsComplete: function(){
return this.state.isComplete ? 'is-complete' : '';
},
render: fucntion(){
return <div className={this.getIsComplete()}></div>; // 直接使用函式
}
&& operator
上述範例遇到值為null或是false的狀況不會輸出任何東西,這時可用&&
運算子省略原範例的''
寫法
render: function(){
return <div className={this.state.isComplete && 'is-complete'}></div>
}
範例表示 this.state.isComplete
為 true
才會使用字串 is-complete
。
Non-DOM 特殊屬性
- key
- ref
- dangerouslySetInnerHTML
key
用來唯一識別元件
ref
即參考(reference)。 ref 允許父元件保存一個指向子元件的參考,以便在渲染函式外使用,ref的定義方式如下:
render: function () {
return <div>
<input ref="myInput" ... />
</div>;
}
之後可在任一元件用 this.refs.myInput
存取這個參考。透過這個參考存取的物件稱為「支援實作(backing instance)」。要注意的是,它不是實際的DOM,若要存取實際的DOM節點可用 this.refs.myInput.getDOMNode()
。
dangeouslySetInnerHTML
此JSX特殊屬性是用來設置原生的HTML,可於要用字串操作DOM的第三方函式庫的時候,利用此屬性設定HTML內容為字串。要注意的是,此屬性不推薦且應避免使用。使用方式如下先設置包含 __html
的物件,再指定給此屬性。
render: function () {
var htmlString = {
__html: "<span>this is an html string</span>"
};
return <div dangeouslySetInnerHTML={htmlString}></div>;
}
※這個設置HTML字串的方式似乎有其他解法
事件
- onClick
- onChange
- Class component事件的正確範例:
handleClick: function (e) {...}; render: function () { return <div onClick={this.handleClick}>...</div>; }
- Class component事件的錯誤範例:由於React會自動綁定(bind)一個元件的所有方法,所以不必特地手動綁定函式的執行環境。
handleClick: function (e) {...}; render: function () { return <div onClick={this.handleClick.bind(this)}> // incorrect }
註解
// 1. 子節點
<div>
{/*
comment
*/}
<input name="email" placeholder="Email Address" />
</div>
// 2. 內嵌於屬性
<div>
<input
/*
多行註解
*/
name="email"
placeholder="Email Address" />
</div>
<div>
<input
name="email" // 單行註解
placeholder="Email Address" />
</div>