- react 基本概念解析
- react 的組件聲明周期
- react 高階組件,context, redux 等高級進(jìn)階
特別提醒:
新版本更新
React.createClass({ ..... }) 為es5 的寫法,新版已經(jīng)被廢棄
class { ..... } 為 es6 的寫法,推薦使用create-react-app 工程為自動創(chuàng)建新 react 工程的工具項(xiàng)目,該工具包含了打包、 測試、sourceMap、等功能。
react 使用全家桶(
react 項(xiàng)目中不可或缺的工具
)
React 在開發(fā)/生產(chǎn) 階段需要一大堆的工具庫輔助開發(fā)
編譯:babel
狀態(tài)管理工具:redux
單頁應(yīng)用:react-routedangerouslySetInnerHTML 用于設(shè)置不受保護(hù)的HTML
<div dangerouslySetInnerHTML = {{ __html: this.state.不受保護(hù)的代碼片段 }}></div>-
好的 React 命名習(xí)慣
- 自定義的組件使用 首字母大寫的駝峰命名 (eg:
InputComponent
..... ) - 自定義的屬性使用 小駝峰命名 ( eg: this.state.
getDate
..... ) - 事件盡可能以 handle... 開頭命名 (eg: handleChange....)
- 組件私有的自定方法以下劃線 _..... 開頭命名 (eg: _getLocalDate...... )
- 自定義的組件使用 首字母大寫的駝峰命名 (eg:
react 概念大全
事件系統(tǒng) + 表單應(yīng)用 + 樣式處理 + 組件通訊 + 組件抽象 + 組件性能優(yōu)化 + 動畫 + 自動化測試
一:react 基本概念解析
- react 描述 DOM 的 方式 (JSX)jsx 其實(shí)就是 JavaScript 對象
-
在 javascript 中使用類似于 HTML 結(jié)構(gòu)和信息的語法為 JSX 語法。
很容易轉(zhuǎn)換編譯成為 于 HTML 信息的 JavaScript 表示形式( `HTML 的 對象形式` )。 可以根據(jù)平臺 編譯成為 第三方頁面 UI 結(jié)構(gòu)
ReactDOM 解析
ReactDOM 是 react 提供的 WEB 頁面構(gòu)建對, 在 移動端 該對象是 ReactApp
ReactDom 有三個方法:
findDomNode( this ) // 用于獲取頁面中的DOM 元素
UnmountComponentAtNode()
render() // 用于頁面渲染-
ref 和 findDomNode 獲取頁面元素辨析
ref 添加到 Component 上獲取的是 Component 實(shí)例,
ref 添加在 原生的 HTML 上獲取的是 DOM 節(jié)點(diǎn)findDomNode 當(dāng)參數(shù)是 DOM 時 就返回一個 DOM( 貌似沒什么用 ) findDomNode 當(dāng)參數(shù)是 Component 時返回 Component 中的 render 中的 DOM <div> <div ref={div => { this._div = div }}>app </div> <Child ref={child => this._child = child}/> <button onClick={()=> { console.log(ReactDOM.findDOMNode(this._div) === this._div); console.log(ReactDOM.findDOMNode(this._child)); }}>log refs </button> </div>
特點(diǎn)
1. react 使用 jsx 描述 DOM / UI 結(jié)構(gòu)
2. jsx 預(yù)防在編譯階段 會轉(zhuǎn)換為 DOM 的 JavaScript 表現(xiàn)形式
3. ReactDom 對象只有一個作用 ---> 負(fù)責(zé)將 JavaScript 對象 渲染成為 真正的頁面 DOM
4. 在渲染過程中 react-dom( web ) ,react-canvas( canvas ) ,react-app (react-native) 可分別將該 JS 對象渲染到不同的平臺上
- render 函數(shù)中都可以寫什么
render 函數(shù)能且只能 返回一個 jsx 對象, 就是必須 返回一個值,并且這個值 是一個 類似于 DOM 的 jsx 語法
-
jsx 結(jié)構(gòu)中可以使用 { } ( 大括號 ) 插入 表達(dá)式
{ } 大括號中 可以放置任何表達(dá)式內(nèi)容( 包括 函數(shù),jsx 結(jié)構(gòu),變量,對象,表達(dá)計(jì)算式 )
... render () { const isGoodWord = true return ( <div> React 小書 { // jsx 中的注釋 只能寫在 大括號中 // 下面表示一個三目表達(dá)式 // 這里不能寫 JavaScript 的 多行表達(dá)式 isGoodWord ? <strong> is good</strong> : <span> is not good</span> } { // 下面表示一個自執(zhí)行函數(shù),函數(shù)中可以做任何你想做的事,也可以有多行代碼 (function() { .... doSomething }) } </div> ) } ...
jsx 結(jié)構(gòu)中的 null 表示什么都不顯示,相當(dāng)于忽略了該表達(dá)式的插入,可以使用這個
特性來 隱藏元素
-
jsx 結(jié)構(gòu)整體當(dāng)做變量用于 參數(shù)傳遞或者使用
jsx 語法其實(shí)就是一個個 js 的對象,所以可以使用任何變量能使用的方式傳遞或者使用它們
... render () { const isGoodWord = true const goodWord = <strong> is good</strong> // 這是一個 jsx 變量 const badWord = <span> is not good</span> // jsx 變量還可以當(dāng)做 函數(shù)參數(shù)傳遞 return ( <div> React 小書 {isGoodWord ? goodWord : badWord} </div> ) } ...
-
在 render 的 {} 中 可以使用 map 等
返回 DOM LIST
的函數(shù)方法// 必須返回一個 表示 DOM LIST const arr = [1, 2, 3, 4, 5]; render () { return ( <select> this.arr.map((item) => <option>item</option> ) </select> ) } ...
jsx 中的 三元表達(dá)式 其實(shí)就是一句完整的表達(dá)式,所以可以被 識別
-
jsx 語法中 注釋的寫法
注釋只能寫在 JavaScript 表達(dá)體 中(
即只能 寫在 { } 大括號中
),寫在 大括號外面的注釋不被識別
要是真的想寫注釋,可以給某個或者某條語句外面添加一個 大括號,然后在進(jìn)行注釋 組件嵌套
組件和組件之間可以 嵌套使用。但是所有的自定義組件都必須是以 大寫字母開頭的組件。
-
事件系統(tǒng)
每個 jsx 元素上面都可以自己定義 on* 類型的事件監(jiān)聽函數(shù),只能用在普通的 html 元素標(biāo)簽上,不能使用在自定義的元素標(biāo)簽上
每個事件監(jiān)聽函數(shù) 都有一個默認(rèn)的 event 對象。
一個經(jīng)過 react 包裝的 event 對象
react 的事件代理機(jī)制
react 將事件處理函數(shù)統(tǒng)一綁定在最外層上面
react 對于原生的 DOM 節(jié)點(diǎn)可以書寫原生的事件
** 特別注意 **:因?yàn)?react 的事件代理機(jī)制,注意 stopPropagation() 阻止事件冒泡的時機(jī)
-
注意 每個 事件監(jiān)聽函數(shù) 若內(nèi)部有使用到 this 的情況,需要在聲明函數(shù)的地方,動態(tài)的綁定 this
// bind this 的時候 可以 傳遞默認(rèn)的 參數(shù) render () { return ( <h1 onClick={this.handleClickOnTitle.bind(this, 'Hello')}>React 小書</h1> ) }
react 的 this 自動綁定區(qū)域
A. class 內(nèi)部自動綁定 this (class 的 { } 大括號這一層級 自動綁定 this
)
B. 構(gòu)造函數(shù) constructor 中沒有自動綁定this
C. 箭頭函數(shù)自動綁定this
D. 使用 bind 顯示綁定 this
-
state 的 使用
- 每次調(diào)用 setState 都會觸發(fā) react 的重新渲染,并且重新調(diào)用 render 方法 **
- setState 函數(shù)執(zhí)行時可以接受一個參數(shù)(prevState)
- 多個 setState 執(zhí)行需要合并時 需要 prevState 參數(shù)的幫忙。并且
react 會將 多個 setState 操作合并為一個最終的狀態(tài)進(jìn)行一次性渲染
- react 自己的 diff 算法保證只會渲染更改的地方
- props 的使用
props 帶來更好的復(fù)用性和 可配置性
defaultProps設(shè)置組件默認(rèn)的 props, 和 this.props 獲取配置參數(shù),設(shè)定 組件的默認(rèn) props 數(shù)據(jù)
組件內(nèi)部一旦傳遞進(jìn) props
不可以在組件內(nèi)部更改 props
。
但是 組件內(nèi)部 可以獲取 props. 將其賦予 state 或者 其他變量進(jìn)行數(shù)據(jù)的增刪改。
組件的生命周期
- 前端的狀態(tài)數(shù)據(jù)管理, - 狀態(tài)提升
將組件之間共享的數(shù)據(jù)抽象并提取出來放到最近的 公共父節(jié)點(diǎn)上,然后通過 props 將數(shù)據(jù)傳遞給子組件, 這樣就是一個狀態(tài)數(shù)據(jù)的提升。
那么問題來了? 怎樣管理 多個層次的組件 所依賴的狀態(tài)呢 ?
( ** 請大家關(guān)注 context 和 redux 的相關(guān)內(nèi)容 ** )
- 組件的基礎(chǔ)生命周期
react 將組件渲染 并塞到 DOM 元素中然后繪畫在頁面上的過程稱為組件的掛載
所以 由掛載的過程你可以很好的理解下面的組件處理過程
constructor() // 初始化狀態(tài)數(shù)據(jù)
componentWillMount() // 組件的掛載過程
render()
// 構(gòu)造 DOM 元素 插入頁面
componentDidMount() // 組件的掛載過程
。。。。。
// 即將從頁面中刪除元素
componentWillUnmount()
// 從頁面中刪除元素
以上 的幾個生命周期 都是 組件的 第一階段的狀態(tài)管理函數(shù)
,
- 一般的 getDefaultProps 和 getInitialState 都會放在 constructor 中完成
- 組件的隱藏 會觸發(fā) 頁面的 componentWillUnmount() 函數(shù),所以,在頁面被隱藏時要注意剩余數(shù)據(jù) 的處理。
- componentWillMount() 函數(shù)多用于組件的啟動,eg: ajax, localStore數(shù)據(jù)的拉取,定時器的啟動,等工作。
- componentDidMount() 函數(shù)用于依賴 DOM 的事件動作或者其他。eg: 動畫的啟動需要依賴 DOM. componentWillMount 的時候 DOM 還沒有掛載完成,所以動畫的啟動需要放在 DidMount 函數(shù)中完成
-
組件更新的生命周期
shouldComponentUpdate(nextProps, nextState)
返回一個 boolean 數(shù)據(jù)
。 用于控制組件是否 重新渲染。
componentWillReceiveProps(nextProps). 多用于處理父組件傳遞過來的 props
componentWillUpdate(); 組件開始更新之前調(diào)用。
componentDidUpdate(); 組件更新并且重新渲染到 DOM 之后調(diào)用。 ref 的作用
ref 屬性用于獲取已經(jīng)掛載的 DOM 節(jié)點(diǎn)( 類似于為元素添加 id 屬性,用于表示元素
)
refs 用于引用已經(jīng) 標(biāo)識的 DOM 節(jié)點(diǎn),獲取其 對象的 屬性 和 方法
** 注意: ** 多余 的 DOM 操作 會產(chǎn)生代碼的噪音,不推薦大量使用 ref 操作 DOM
ref 版本改動:標(biāo)識 DOM 節(jié)點(diǎn)的 ref由原來的字符串改為一個回調(diào)函數(shù)
舊版本 <input ref="myinput" />
新版本 <input ref={(input)=>{this.myinput=input;}}/>可以額外有一個參數(shù)
參數(shù)有妙用
- props.children 和 自定義標(biāo)簽元素中 添加 額外的 HTML DOM 元素
普通的標(biāo)簽元素中內(nèi)嵌的 DOM 元素可以直接添加。但是自定義標(biāo)簽組件怎講將內(nèi)嵌的 DOM 內(nèi)容傳遞到下一層呢?
我們使用 props.children 可以獲取到上層的 自定義標(biāo)簽中的內(nèi)嵌的 DOM 元素
-
jsx 中任何的 html 格式的 代碼都會被轉(zhuǎn)義掉,為了防止 xss 攻擊
為了顯示 帶有 html 標(biāo)簽的元素我們需要用到元素的 dangerouslySetInnerHTML (
這個只是元素的一個屬性
)..... render() { renturn ( <div className="edit-html" // 按照下面的方法設(shè)置元素的 html 的內(nèi)容 dangerouslySetInnerHtml={ { __html: this.state.content } } > ) } .....
-
propsTypes 和 組件的參數(shù)驗(yàn)證
JavaScript 是弱類型的語言,但是為了 ** 防止和校驗(yàn)上一層傳遞過來數(shù)據(jù)的正確性,我們使用 PropTypes 來做數(shù)據(jù)類型的校驗(yàn)相當(dāng)于為數(shù)據(jù)添加數(shù)據(jù)類型,強(qiáng)類型的數(shù)據(jù)
**import React, { Component, PropTypes } from 'react' .... class ChildComponent extends Component { // 下面這些是固定的 書寫格式 static propsTypes = { parentAttr: PropTypes. object, parentArr: PropTypes.array } ......... } ......
-
高階組件就是一個函數(shù),你傳遞給他一個組件對象,他返回給你一個經(jīng)過包裝的組件對象
** 相當(dāng)于在原始組件之上 添加了一層經(jīng)過封裝的父組件 **功能性的封裝
** 作用:**
組件狀態(tài)提升
將子組件需要操作的數(shù)據(jù)交給父組件來管理,然后通過 props 向下傳遞數(shù)據(jù)。此為狀態(tài)提升
當(dāng)某個數(shù)據(jù)/狀態(tài) 被多個組件依賴/使用 時,應(yīng)該通過狀態(tài)提升來管理-
高階組件本質(zhì)就是為了
組件之間的復(fù)用
,將重復(fù)的代碼 操作放在高階組件中,下面的基本組件就可以復(fù)用了比如數(shù)據(jù)的 ajax 的讀取,事件的統(tǒng)一操作等
高階組件中 通過 props 傳遞數(shù)據(jù)
-
高階組件可以很好的實(shí)現(xiàn) Smart 組件( 依賴數(shù)據(jù)操作的組件/ 高階組件 ) 和 Dumb 組件( 只需要上層數(shù)據(jù)props的純組件 ) 的分離
Smart 組件和 Dumb 組件( 或者說高階組件 )的出現(xiàn),很好的實(shí)現(xiàn)了 react 的 mvc 結(jié)構(gòu),達(dá)到了高層次的 組件的復(fù)用。
高階組件知識點(diǎn)
1. 高階組件 本質(zhì)就是一種 組件的 mixin 模式
1. es7 的裝飾著模式可以用來擴(kuò)展高階組件
2. 一個 Smart 組件可以被多個高階組件裝飾,并且按照順序執(zhí)行
-
react 的 context 作為全局的對象,有自己獨(dú)特的寫法
** context 必須和 propType 強(qiáng)制數(shù)據(jù)類型 共同使用 **
強(qiáng)制數(shù)據(jù)類型
import React, { Component, PropTypes } from 'react'
......
static propsTypes = {
themeColor: PropTypes. string
}-
定義context 時的寫法
import React, { Component, PropTypes } from 'react' .... class ParentComponent extends Component { // 下面這些是固定的 書寫格式 static propsTypes = { themeColor: PropTypes. string } ......... // 這里設(shè)置了 本組件包括其 所有子組件的 context getChildContext () { return { themeColor: this.state.themeColor } } } ......
context 在定義時,必須有兩個步驟
聲明屬性的數(shù)據(jù)類型
設(shè)置獲取全局 Context 的方法 getChildContext-
使用 context
import React, { Component, PropTypes } from 'react' .... class ChildComponent extends Component { static propsTypes = { themeColor: PropTypes. string } render () { return ( <div style={{ color: this.context.themeColor }}>context 的獲取使用地方</div> ) } }
context 在使用時必須有兩個步驟
聲明要使用的 context 數(shù)據(jù)類型
使用 this.context.屬性 獲取屬性的值
context 使用步驟繁雜是有原因的
1. context 作為全局擁有的對象,必須保證其數(shù)據(jù)的正確性。
2. react 官方不推薦使用 context, 進(jìn)而希望大家能夠使用更為友好的Redux, Mobx等
React 組件進(jìn)階
-
react 理念分析
React 的組件本質(zhì)是創(chuàng)建了一個對象,由框架本身添加了 10 個聲明周期函數(shù)(
其實(shí)就是普通的函數(shù),只是有執(zhí)行順序、觸發(fā)時機(jī)、優(yōu)化處理等特點(diǎn)
)
具體參見 React 的最初寫法 React.createClass({ .... }), 中間是一個對象聲明周期函數(shù),就是對象中的普通函數(shù)
傳值 + 操作處理 + 返回值-
react 特點(diǎn):
1. 簡潔: 足夠的簡潔,其本身只有自己的 api
2. 非聲明式的單項(xiàng)數(shù)據(jù)綁定
3. ** 面向 HTML5, 專注視圖層操作 ** 將 JavaScript 和 HTML5 整合在一起。
4. 高性能的密集 DOM 操作
5. 支持后端渲染。
6. 跨平臺,一種書寫,能夠編譯出多種結(jié)果 ** ReactNative **react 函數(shù)式編程 ( 小函數(shù)編程 )
1. 盡可能抽象出公共使用的小函數(shù)。
2. 在一個龐雜的 邏輯體 中能夠提取出 功能小函數(shù) -
組件化
狹義的組件化:ui組件 ---> 具體的組件( Tabs 組件 / Dropdown 組件 )
廣義的組件化: 業(yè)務(wù)數(shù)據(jù) + UI 組件的組合使用組件化的發(fā)展進(jìn)程
DOM操作為主
( 根據(jù)邏輯改變 DOM 結(jié)構(gòu) )
--> MVC( 數(shù)據(jù)和界面解耦 )
--> 小組件( 數(shù)據(jù) + 界面 + 樣式的結(jié)合體 eg: angular 指令 )
----> HTML5 的引入( javascript + HTML + css 合為一體)
HTML Templetes --> custom Element --> shadow DOM --> HTML Imports
-
** 非常重要:**
** 組件封裝的進(jìn)程其實(shí)就是面向?qū)ο蟮乃枷胫鸩匠墒?* (通過實(shí)例化的方法制造對象
)一個組件的對象實(shí)例: ( 基本的封裝性 + 簡單的聲明周期 + 明確的數(shù)據(jù)流動 )
-
表單組件
表單組件分為受控組件和非受控組件
受控組件:依靠 state 和內(nèi)部事件 改變狀態(tài)的組件,有很強(qiáng)的耦合性,復(fù)用性不高非受控組件,通過 defaultProps, props 傳值的組件,復(fù)用性好 非受控組件可以通過 事件和 ref 向上傳遞數(shù)據(jù)
組件通訊 ---> 事件訂閱
EventEmitter-
組件性能優(yōu)化
引入純函數(shù)( pureRender 函數(shù)或者 Smart組件 )
使用 數(shù)據(jù)對比決定 純函數(shù)組件是否渲染
shouldComponentUpdate()
-
引入不可變對象 或者 es6 對象擴(kuò)展 進(jìn)行數(shù)據(jù)對比
Immutable 不可變對象,對 Immutable 對象的 增 刪 改 都會生成一個新對象,類似于對象的深拷貝,但是比對象的深拷貝效率要高 es6 對象擴(kuò)展 和 對象/數(shù)組的解構(gòu)賦值,也能夠得到一個新的對象
-
Immutable 解析
** Immutable 可以提供一種全新的數(shù)據(jù)對比和生成形式,類似于 es6 的對象擴(kuò)展 和 解構(gòu)賦值 **
Immutable 三種數(shù)據(jù)類型 Map: 對應(yīng)于 `Object`, 鍵值對集合 List : 對應(yīng)于 `Array` 有序的重復(fù)列表 ArrayList: 無序不可重復(fù)的列表 // 特性應(yīng)用實(shí)例 import { Map, List, Arraylist } from 'immutable' .... this.setSatate({ data: Map({ times: 0 }) // 得到一個新的 Immutable 對象 })
Immutable 方法應(yīng)用實(shí)例 ( Immutable.is 可以用來進(jìn)行比較,比 === 全等的效率高 )
import { is } from 'immutable' ..... shouldComponentUpdate(nextProps, nextState) { if( is( nextProps.attr, nextState.attr ) ) return false; ...... }
.