### 聲明式開發
- 命令式開發:原生js和jq寫代碼的時候,大部分代碼都是在操作dom,這種開發模式就是命令式開發。
- 聲明式開發:react是面向數據編程,不需要直接去控制dom,你只要把數據操作好,react自己回去幫你操作dom,可以節省很多操作dom的代碼。這就是聲明式開發。
### 可以和其他框架並存
- react所控制的dom就是id為root的dom,頁面上的其他dom元素你頁可以使用jq等其他框架。所以react是可以和其他框架並存的。
### 組件化
- 在我們寫todo-list的時候,我們已經使用react的組件了。通過繼承react的Component去創建一個組件。
### 單向數據流
- react是單向數據流,父組件傳遞給子組件的數據,子組件能夠使用,但是不能直接通過this.props修改。否則會報錯。(cannot assign to read only property ‘xxx’ of object ‘#object’)
- 子組件要傳值給父組件,或者要修改父組件的代碼,都是要通過父組件傳遞過來的方法去實現。
- 這樣的好處在於,讓數據清晰代碼容易維護,如果每個子組件都能直接修改父組件的數據,當子組件躲起來代碼維護起來很麻煩。
### react是視圖層框架
- 結合上面講的單向數據流,如果是大型項目,非常多的子組件,要修改一個公共的參數,就需要很多層的傳遞才能完成一個數據變更。
- 單單react去做大型項目是不夠的,他優勢在於視圖層的渲染,涉及到復雜的數據傳遞,還需要結合其他數據層的框架開發。如mox-box,redux。
### 函數式編程
- react項目中大部分都是函數,連html都是由render函數去實現的。
- 他的優勢在於,方便代碼維護,復雜的函數可以拆分成多個函數。
- 在前端自動化測試也很方便,只需要給函數一個參數,看他的輸出就可以了。
### react開發調試工具
- react Developer Tools (需要翻牆,在谷歌瀏覽器應用商店)
### propTypes 與 DefaultProps
/** - value: PropTypes.string.isRequired --> value是父組件傳遞過來的參數,子組件規定value必須是字符串,並且必須傳遞(isRequired) - deletItem: PropTypes.arrayOf(PropTypes.string,PropTypes.func) --> deletItem必須是方法,或者字符串 - 更多類型參考官方文檔 --> https://react.docschina.org/docs/typechecking-with-proptypes.html */ import React, {Component, Fragment} from 'react'; import PropTypes from 'prop-types'; //引入propTypes class Item extends Component { deletItem = () => { const { deletItem, index } = this.props; deletItem(index); } render(){ const { value } = this.props return( <Fragment> <div onClick = {this.deletItem} > {value} </div> </Fragment> ) } } Item.prototypes = { test: PropTypes.string.isRequired, value: PropTypes.string.isRequired,//定義傳遞過來的value參數必須是字符串 deletItem: PropTypes.arrayOf(PropTypes.string,PropTypes.number),// 必須是方法或者字符串的數組 deletTtem: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, PropTypes.instanceOf(Message) ]),// 必須是這些類型的中的一個。 index: PropTypes.number // 必須是數字 } Item.defaultProps = { test: 'defaultProps' // 為test設置默認值,如果沒有傳入test,就使用這個默認值 } export default Item
### Props,State 與 Render 函數之間的關系
- 數據變化為什么視圖會變化?
- react的視圖是通過Render函數去渲染的,組件當中,如果Props或者State有變化,Render函數就會重新執行一次。
- 父組件的Render重新執行,對應的他的子組件中的Render也會重新執行。
### 什么是虛擬DOM
1. 先有數據 (state)
2. 模版(render中的jsx)
3. 數據 + 模版 = 生成真實Dom,來顯示
4. state 發生改變
5. 數據 + 模版 = 生成真實Dom,替換原有的DOM
- 缺陷: 第一次生成真實dom,第二次又生成一個。最后替換。非常耗性能。
- 原因: 生成一個完整的dom,和替換一個完整的dom,非常耗性能。並不是每次數據變化dom的所有內容都要變。
1. 先有數據 (state)
2. 模版(render中的jsx)
3. 數據 + 模版 = 生成真實Dom,來顯示
4. state 發生改變
5. 數據 + 模版 = 生成真實Dom,並不直接替換原始的DOM
6. 新舊DOM做對比,找差異。注意新的DOM其實是DoucumentFragment: 文檔碎片並沒有真實的掛載到頁面上。
7. 找出input框發生變換
8. 只用新DOM中的input元素,替換掉老的DOM中的input元素。
- 缺陷: 節約了完整dom替換的性能,但是消耗了對比的性能。效果不明顯。
1. 先有數據 (state)
2. 模版(render中的jsx)
3. 數據 + 模版 = 生成真實Dom,來顯示
1. <div id='abc'><span>hello,world</span></div>
4. 生成虛擬DOM(生成虛擬DOM是一個js對象,用它來描述真是DOM)(損耗性能非常小)
1. ['div', {id: 'abc'}, ['span', {}, 'hello,world']]
5. state 發生改變
6. 數據 + 模版 = 生成新的虛擬DOM(極大提升了性能)
1. ['div', {id: 'abc'}, ['span', {}, 'bye,bye']]
7. 比較原始虛擬DOM和新的虛擬DOM的區別,找到區別是span中的內容
8. 直接操作DOM改變span中的DOM
- 優勢:
1. 減少了對真實DOM的創建性能提高很大
2. js對象的比對非常不消耗性能的。
- 原因:
1. js去生產一個虛擬DOM其實就是一個js對象,而使用js去生成一個js對象是不怎么消耗性能的。
2. 對比上面兩種方法,不僅減少了真實DOM的生產,同時也沒有了真實DOM的對比,虛擬DOM對比也是非常節約新能的。