## 1. 幾個重要概念理解
* 模塊與組件
* 模塊:
* 理解: 向外提供特定(局部)功能的js程序, 一般就是一個js文件
* 為什么: js代碼更多更復雜
* 作用: 復用js, 簡化js的編寫, 提高js運行效率
* 組件:
* 理解: 用來實現特定功能效果的代碼集合(html/css/js)
* 為什么: 一個界面的功能更復雜
* 作用: 復用編碼, 簡化項目編碼, 提高運行效率
* 模塊化與組件化
* 模塊化:
* 當應用的js都以模塊來編寫的, 這個應用就是一個模塊化的應用
* 組件化:
* 當應用是以多組件的方式實現功能, 這上應用就是一個組件化的應用
## 2. React的基本認識
* 一個用來動態構建用戶界面的js庫
* React的特點
* Declarative(聲明式編碼)
* Component-Based(組件化編碼)
* Learn Once, Write Anywhere(支持客戶端與服務器渲染)
* 單向數據流(只支持M->V)
* React高效的原因
* 虛擬(virtual)DOM, 不總是直接操作DOM(批量更新, 減少更新的次數)
* 高效的DOM Diff算法, 最小化頁面重繪(減小頁面更新的區域)
## 3. 使用React
* 導入相關js庫文件(react.js, react-dom.js, babel.min.js)
* 編碼:
```
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>02_JSX</title>
</head>
<body>
<div id="example1">abc</div>
<div id="example2"></div>
<script type="text/javascript" src="../js/react.js"></script>
<script type="text/javascript" src="../js/react-dom.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
//React.createElement創建虛擬DOM對象
let element1 = React.createElement('h2', {id: 'ele1', className: 'ele1', name: 'hello'}, ' React.createElement');
// jsx語法創建虛擬DOM對象
let msg = 'jsx語法創建虛擬DOM對象';
let element2 = <h2>{msg}</h2>;
// 渲染虛擬DOM對象
ReactDOM.render(element1, document.getElementById('example1'));
ReactDOM.render(element2, document.getElementById('example2'));
</script>
</body>
</html>
```
## 4. JSX
* 全稱: JavaScript XML
* react定義的一種類似于XML的JS擴展語法: XML+JS
* 作用: 用來創建react虛擬DOM(元素)對象
* js中直接可以套標簽, 但標簽要套js需要放在{}中
* 在解析顯示js數組時, 會自動遍歷顯示
* 把數據的數組轉換為標簽的數組:
```
var liArr = dataArr.map(function(item, index){
return <li key={index}>{item}</li>
})
```
* 注意:
* 標簽必須有結束
* 標簽的class屬性必須改為className屬性
* 標簽的style屬性值必須為: {{color:'red', width:12}}
## 5. 虛擬DOM
* 虛擬DOM是什么?
* 一個虛擬DOM(元素)是一個一般的js對象, 準確的說是一個對象樹(倒立的)
* 虛擬DOM保存了真實DOM的層次關系和一些基本屬性,與真實DOM一一對應
* 如果只是更新虛擬DOM, 頁面是不會重繪的
* Virtual DOM 算法的基本步驟
* 用 JavaScript 對象結構表示 DOM 樹的結構;然后用這個樹構建一個真正的 DOM 樹,插到文檔當中
* 當狀態變更的時候,重新構造一棵新的對象樹。然后用新的樹和舊的樹進行比較,記錄兩棵樹差異
* 把2所記錄的差異應用到步驟1所構建的真正的DOM樹上,視圖就更新了
* 進一步理解
* Virtual DOM 本質上就是在 JS 和 DOM 之間做了一個緩存。
* 可以類比 CPU 和硬盤,既然硬盤這么慢,我們就在它們之間加個緩存:既然 DOM 這么慢,我們就在它們 JS 和 DOM 之間加個緩存。CPU(JS)只操作內存(Virtual DOM),最后的時候再把變更寫入硬盤(DOM)。
## 6. Component : React是面向組件編程的(組件化編碼開發)
* 基本理解和使用
* 自定義的標簽: 組件類(函數)/標簽
* 創建組件類
```
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>03_component_basic</title>
</head>
<body>
<div id="example1">abc</div>
<div id="example2"></div>
<div id="example3"></div>
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">
// 創建組件
//方式1: 工廠(無狀態)函數(最簡潔, 推薦使用)
function MyComponent1() {
console.log('MyComponent1()');
return <h1>工廠(無狀態)函數(最簡潔, 推薦使用)</h1>
}
// 方式2: ES6類語法(復雜組件, 推薦使用)
class MyComponent2 extends React.Component{
add(){
}
render(){
console.log(this);
return <h2>ES6類語法(復雜組件, 推薦使用)</h2>
}
}
// 渲染組件
ReactDOM.render(<MyComponent1 />, document.getElementById('example1'));
ReactDOM.render(<MyComponent2 />, document.getElementById('example2'));
</script>
</body>
</html>
```
* ReactDOM.render()渲染組件標簽的基本流程
* React內部會創建組件實例對象/調用組件函數, 得到虛擬DOM對象
* 將虛擬DOM并解析為真實DOM
* 插入到指定的頁面元素內部
* props
* 所有組件標簽的屬性的集合對象
* 給標簽指定屬性, 保存外部數據(可能是一個function)
* 在組件內部讀取屬性: this.props.propertyName
* 作用: 從目標組件外部向組件內部傳遞數據
* 對props中的屬性值進行類型限制和必要性限制
```
Person.propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number.isRequired
}
```
* 擴展屬性: 將對象的所有屬性通過props傳遞
```
<Person {...person}/>
```
* 組件的組合
* 組件標簽中包含子組件標簽
* 拆分組件: 拆分界面, 抽取組件
* 通過props傳遞數據
* refs
* 組件內包含ref屬性的標簽元素的集合對象
* 給操作目標標簽指定ref屬性, 打一個標識
* 在組件內部獲得標簽對象: this.refs.refName(只是得到了標簽元素對象)
* 作用: 操作組件內部的真實標簽dom元素對象
* 事件處理
* 給標簽添加屬性: onXxx={this.eventHandler}
* 在組件中添加事件處理方法
```
eventHandler(event) {
}
```
* 使自定義方法中的this為組件對象
* 在constructor()中bind(this)
* 使用箭頭函數定義方法(ES6模塊化編碼時才能使用)
* state
* 組件被稱為"狀態機", 頁面的顯示是根據組件的state屬性的數據來顯示
* 初始化指定:
```
constructor() {
super();
this.state = {
stateName1 : stateValue1,
stateName2 : stateValue2
};
}
```
* 讀取顯示:
this.state.stateName1
* 更新狀態-->更新界面 :
this.setState({stateName1 : newValue})
* 實現一個雙向綁定的組件
* React是單向數據流
* 需要通過onChange監聽手動實現
* 組件生命周期
* 組件的三個生命周期狀態:
* Mount:插入真實 DOM
* Update:被重新渲染
* Unmount:被移出真實 DOM
* 生命周期流程:
* 第一次初始化顯示
```
constructor()
componentWillMount() : 將要插入回調
render() : 用于插入虛擬DOM回調
componentDidMount() : 已經插入回調
```
* 每次更新state
```
componentWillReceiveProps(): 接收父組件新的屬性
componentWillUpdate() : 將要更新回調
render() : 更新(重新渲染)
componentDidUpdate() : 已經更新回調
```
* 刪除組件
```
ReactDOM.unmountComponentAtNode(document.getElementById('example')) : 移除組件
componentWillUnmount() : 組件將要被移除回調
```
* 常用的方法
```
render(): 必須重寫, 返回一個自定義的虛擬DOM
constructor(): 初始化狀態, 綁定this(可以箭頭函數代替)
componentDidMount() : 只執行一次, 已經在dom樹中, 適合啟動/設置一些監聽
```
## 7. ajax
* React沒有ajax模塊
* 集成其它的js庫(如axios/fetch/jQuery/), 發送ajax請求
* axios
* 封裝XmlHttpRequest對象的ajax
* promise
* 可以用在瀏覽器端和服務器
* fetch
* 不再使用XmlHttpRequest對象提交ajax請求
* fetch就是用來提交ajax請求的函數, 只是新的瀏覽才內置了fetch
* 為了兼容低版本的瀏覽器, 可以引入fetch.js
* 在哪個方法去發送ajax請求
* 只顯示一次(請求一次): componentDidMount()
* 顯示多次(請求多次): componentWillReceiveProps()