React中的核心概念
阿新 • • 發佈:2018-12-10
React中的核心概念
* 1 用 JavaScript 物件結構表示 DOM 樹的結構,然後用這個樹構建一個真正的 DOM 樹,插到文件當中Diff演算法 當你使用React的時候,在某個時間點 render() 函式建立了一棵React元素樹, 在下一個state或者props更新的時候,render() 函式將建立一棵新的React元素樹, React將對比這兩棵樹的不同之處,計算出如何高效的更新UI(只更新變化的地方) Diff演算法的說明 - 1* 2 當狀態變更的時候,重新構造一棵新的物件樹。然後用新的樹和舊的樹進行比較,記錄兩棵樹差異 * 3 把2所記錄的差異應用到步驟1所構建的真正的DOM樹上,檢視就更新了
// 舊樹 <div> <Counter /></div> // 新樹 <span> <Counter /></span> 執行過程:destory Counter -> insert CounterDiff演算法的說明 - 2 * 對於型別相同的React DOM 元素,React會對比兩者的屬性是否相同,只更新不同的屬性 * 當處理完這個DOM節點,React就會遞迴處理子節點。
// 舊 <div className="before" title="stuff" /> // 新 <div className="after" title="stuff" /> 只更新:className 屬性 // 舊 <div style={{color: 'red', fontWeight: 'bold'}} /> // 新 <div style={{color: 'green', fontWeight: 'bold'}} /> 只更新:color屬性Diff演算法的說明 - 3 * 1 當在子節點的後面新增一個節點,這時候兩棵樹的轉化工作執行的很好
// 舊 <ul> <li>first</li> <li>second</li> </ul> // 新 <ul> <li>first</li> <li>second</li> <li>third</li> </ul> 執行過程: React會匹配新舊兩個<li>first</li>,匹配兩個<li>second</li>,然後新增 <li>third</li> tree* 2 但是如果你在開始位置插入一個元素,那麼問題就來了:
// 舊 <ul> <li>Duke</li> <li>Villanova</li> </ul> // 新 <ul> <li>Connecticut</li> <li>Duke</li> <li>Villanova</li> </ul> 在沒有key屬性時執行過程: React將改變每一個子刪除重新建立,而非保持 <li>Duke</li> 和 <li>Villanova</li> 不變key 屬性 為了解決以上問題,React提供了一個 key 屬性。當子節點帶有key屬性,React會通過key來匹配原始樹和後來的樹。
// 舊 <ul> <li key="2015">Duke</li> <li key="2016">Villanova</li> </ul> // 新 <ul> <li key="2014">Connecticut</li> <li key="2015">Duke</li> <li key="2016">Villanova</li> </ul> 執行過程: 現在 React 知道帶有key '2014' 的元素是新的,對於 '2015' 和 '2016' 僅僅移動位置即可* 說明:key屬性在React內部使用,但不會傳遞給你的元件 * 推薦:在遍歷資料時,推薦在元件中使用 key 屬性:<li key={item.id}>{item.name}</li> * 注意:key只需要保持與他的兄弟節點唯一即可,不需要全域性唯一 * 注意:儘可能的減少陣列index作為key,陣列中插入元素的等操作時,會使得效率底下
React的基本使用 * 安裝:npm i -S react react-dom * react:react 是React庫的入口點 * react-dom:提供了針對DOM的方法,比如:把建立的虛擬DOM,渲染到頁面上
// 1. 匯入 react import React from 'react' import ReactDOM from 'react-dom' // 2. 建立 虛擬DOM // 引數1:元素名稱 引數2:元素屬性物件(null表示無) 引數3:當前元素的子元素string||createElement() 的返回值 const divVD = React.createElement('div', { title: 'hello react' }, 'Hello React!!!') // 3. 渲染 // 引數1:虛擬dom物件 引數2:dom物件表示渲染到哪個元素內 引數3:回撥函式 ReactDOM.render(divVD, document.getElementById('app'))createElement()的問題 * 說明:createElement()方式,程式碼編寫不友好,太複雜
var dv = React.createElement( "div", { className: "shopping-list" }, React.createElement( "h1", null, "Shopping List for " ), React.createElement( "ul", null, React.createElement( "li", null, "Instagram" ), React.createElement( "li", null, "WhatsApp" ) ) ) // 渲染 ReactDOM.render(dv, document.getElementById('app'))JSX 的基本使用 * 注意:JSX語法,最終會被編譯為 createElement() 方法 * 推薦:使用 JSX 的方式建立元件 * JSX - JavaScript XML * 安裝:npm i -D babel-preset-react (依賴與:babel-core/babel-loader) 注意:JSX的語法需要通過 babel-preset-react 編譯後,才能被解析執行
/* 1 在 .babelrc 開啟babel對 JSX 的轉換 */ { "presets": [ "env", "react" ] } /* 2 webpack.config.js */ module: [ rules: [ { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }, ] ] /* 3 在 js 檔案中 使用 JSX */ const dv = ( <div title="標題" className="cls container">Hello JSX!</div> ) /* 4 渲染 JSX 到頁面中 */ ReactDOM.render(dv, document.getElementById('app'))JSX的注意點 * 注意 1: 如果在 JSX 中給元素新增類, 需要使用 className 代替 class * 類似:label 的 for屬性,使用htmlFor代替 * 注意 2:在 JSX 中可以直接使用 JS程式碼,直接在 JSX 中通過 {} 中間寫 JS程式碼即可 * 注意 3:在 JSX 中只能使用表示式,但是不能出現 語句!!! * 注意 4:在 JSX 中註釋語法:{/* 中間是註釋的內容 */} React元件 React 元件可以讓你把UI分割為獨立、可複用的片段,並將每一片段視為相互獨立的部分。 * 元件是由一個個的HTML元素組成的 * 概念上來講, 元件就像JS中的函式。它們接受使用者輸入(props),並且返回一個React物件,用來描述展示在頁面中的內容 React建立元件的兩種方式 * 1 通過 JS函式 建立(無狀態元件) * 2 通過 class 建立(有狀態元件) 函式式元件 和 class 元件的使用場景說明: 1 如果一個元件僅僅是為了展示資料,那麼此時就可以使用 函式元件 2 如果一個元件中有一定業務邏輯,需要操作資料,那麼就需要使用 class 建立元件,因為,此時需要使用 state JavaScript函式建立 * 注意:1 函式名稱必須為大寫字母開頭,React通過這個特點來判斷是不是一個元件 * 注意:2 函式必須有返回值,返回值可以是:JSX物件或null * 注意:3 返回的JSX,必須有一個根元素 * 注意:4 元件的返回值使用()包裹,避免換行問題
function Welcome(props) { return ( // 此處註釋的寫法 <div className="shopping-list"> {/* 此處 註釋的寫法 必須要{}包裹 */} <h1>Shopping List for {props.name}</h1> <ul> <li>Instagram</li> <li>WhatsApp</li> </ul> </div> ) } ReactDOM.render( <Welcome name="jack" />, document.getElementById('app') )class建立 在es6中class僅僅是一個語法糖,不是真正的類,本質上還是建構函式+原型 實現繼承
// ES6中class關鍵字的簡單使用 // - **ES6中的所有的程式碼都是執行在嚴格模式中的** // - 1 它是用來定義類的,是ES6中實現面向物件程式設計的新方式 // - 2 使用`static`關鍵字定義靜態屬性 // - 3 使用`constructor`建構函式,建立例項屬性 // - [參考](http://es6.ruanyifeng.com/#docs/class) // 語法: class Person { // 例項的建構函式 constructor constructor(age){ // 例項屬性 this.age = age } // 在class中定義方法 此處為例項方法 通過例項打點呼叫 sayHello () { console.log('大家好,我今年' + this.age + '了'); } // 靜態方法 通過建構函式打點呼叫 Person.doudou() static doudou () { console.log('我是小明,我新get了一個技能,會暖床'); } } // 新增靜態屬性 Person.staticName = '靜態屬性' // 例項化物件 const p = new Person(19) // 實現繼承的方式 class American extends Person { constructor() { // 必須呼叫super(), super表示父類的建構函式 super() this.skin = 'white' this.eyeColor = 'white' } } // 建立react物件 // 注意:基於 `ES6` 中的class,需要配合 `babel` 將程式碼轉化為瀏覽器識別的ES5語法 // 安裝:`npm i -D babel-preset-env` // react物件繼承字React.Component class ShoppingList extends React.Component { constructor(props) { super(props) } // class建立的元件中 必須有rander方法 且顯示return一個react物件或者null render() { return ( <div className="shopping-list"> <h1>Shopping List for {this.props.name}</h1> <ul> <li>Instagram</li> <li>WhatsApp</li> </ul> </div> ) } }