學(xué)習(xí)目的
? ? 熟練使用 React寄猩,并能運(yùn)用 React 做一個(gè)項(xiàng)目顶滩,了解 React 開發(fā)叶洞。
? ? 學(xué)習(xí)技巧鲫凶,用?學(xué)過的相似的知識(shí)技術(shù) 與 新知識(shí)? 相對(duì)比,方便記憶衩辟,比如 拿 Vue 和 React 相對(duì)比螟炫,方便記憶與理解。
React 介紹
????React是 Facebook 開源的一個(gè)js庫艺晴,一個(gè)用于動(dòng)態(tài)構(gòu)建用戶界面的js庫昼钻。
? ? React特點(diǎn)
? ??????虛擬DOM: React也是以數(shù)據(jù)驅(qū)動(dòng)的,每次數(shù)據(jù)變化React都會(huì)掃碼整個(gè)虛擬DOM樹封寞,自動(dòng)計(jì)算與上次虛擬DOM的差異變化然评,然后針對(duì)需要變化的部分進(jìn)行實(shí)際的瀏覽器DOM更新。
? ??????組件化: React可以從功能角度橫向劃分狈究,將UI分解成不同組件碗淌,各組件都獨(dú)立封裝,整個(gè)UI是由一個(gè)個(gè)小組件構(gòu)成的一個(gè)大組件谦炒,每個(gè)組件只關(guān)系自身的邏輯贯莺,彼此獨(dú)立。
? ??????單項(xiàng)數(shù)據(jù)流:React設(shè)計(jì)者認(rèn)為數(shù)據(jù)雙向綁定雖然便捷宁改,但在復(fù)雜場景下副作用也是很明顯,所以React更傾向于單向的數(shù)據(jù)流動(dòng)-從父節(jié)點(diǎn)傳遞到子節(jié)點(diǎn)魂莫。(使用ReactLink也可以實(shí)現(xiàn)雙向綁定还蹲,但不建議使用)
Hello world 開場
JSX 語法(JavaScript XML)
? ? ? ? ?JSX:??react 定義的一種類似于XML的JS擴(kuò)展語法: XML+JS;就是在js 中寫HTML代碼耙考。
? ? ? ? ? 作用:?用來創(chuàng)建react虛擬DOM(元素)對(duì)象谜喊。
? ? ? ? ? 例如:var demo = <h1> Hello JSX! </h1>;
? ? ? ? ? 這種標(biāo)簽語法既?不是字符串?也?不是HTML,它最終產(chǎn)生的就是一個(gè)JS對(duì)象倦始,它可以在JS中 寫 HTML斗遏。
? ????????你可以用 花括號(hào) 把任意的 JS代碼?嵌入到 JSX 中!P亍K写巍!C锻搿S庖弧!0褂辍W穸隆!!
? ? ??????????基本語法規(guī)則
? ? ????????* 遇到 <?開頭的代碼, 以標(biāo)簽的語法解析: html同名標(biāo)簽轉(zhuǎn)換為html同名元素, 其它標(biāo)簽需要特別解析 ; 如果是空標(biāo)簽陌宿,應(yīng)該像 XML 一樣锡足,使用?/>立即閉合它:<img src='' />
? ? ????????* 遇到以 { 開頭的代碼,以JS的語法解析: 標(biāo)簽中的js代碼必須用 { } 包含壳坪。
? ??????????* 注意 !!!!!!!!!!!
? ? ????????* 標(biāo)簽必須有結(jié)束
? ? ????????* 標(biāo)簽的class屬性必須改為className屬性
? ? ????????* 標(biāo)簽的style屬性值必須為: {{color:'red', width:12}}
組件(Components)和 屬性
? ? ? ? 自定義組件(主要有2中形式定義)
? ?? 注意:
? ????1). 返回的組件類必須首字母大寫
? ????2). 嵌套的組件舶得,虛擬DOM元素必須只有一個(gè)根元素
? ????3). 虛擬DOM元素必須有結(jié)束標(biāo)簽? ?/
??組件三大屬性(props,refs弥虐,state)
? ???????①props屬性(只讀)
????????也可以寫成
? ? ? ?1. 每個(gè)組件對(duì)象都會(huì)有props(properties的簡寫)屬性
? ? ? ? 2. 組件標(biāo)簽的所有屬性都保存在props中
? ? ? ? 3. 內(nèi)部讀取某個(gè)屬性值: this.props.屬性名稱
? ? ? ? 4. 作用: 通過標(biāo)簽屬性從組件外向組件內(nèi)傳遞數(shù)據(jù)(只讀)扩灯,我們不應(yīng)該修改props的值!K瘛V椴濉!
? ? ? ? 5. 對(duì)props中的屬性值進(jìn)行?類型限制?和 必要性限制颖对,比如:
? ??????????Person.propTypes = {
? ? ? ????????name:PropTypes.string.isRequired,
? ? ? ????????age: PropTypes.number.isRequired
? ????????? }
? ??????6. 擴(kuò)展屬性: 將對(duì)象的所有屬性通過props傳遞
? ??????7. 默認(rèn)屬性值
? ? ????????Person.defaultProps = {
? ? ? ????????name: 'Lily'
? ????????? };
? ? ? ? ②refs屬性(和 Vue 的refs 基本相同)
? ? ? ? ?1). 組件內(nèi)的標(biāo)簽都可以定義ref 屬性來標(biāo)識(shí)自己?
?????????2). 在組件中可以通過this.refs.refName來得到對(duì)應(yīng)的真實(shí)DOM對(duì)象?
?????????3). 作用: 用于操作指定的ref屬性的dom元素對(duì)象(表單標(biāo)簽居多)?
?????????????????*<input ref='username'/>
????????????????* this.refs.username //返回input對(duì)象
? ???????事件處理?
?????????1). 通過onXxx屬性指定組件的事件處理函數(shù)(注意大小寫,小駝峰命名法)?
? ? ? ? ? ? ?* React使用的是自定義(合成)事件, 而不是使用的DOM事件
?????????????* React中的事件是通過委托方式處理的(委托給組件最外層的元素)? ? ? ? ??
? ? ? ? ? 2). 通過event.target得到發(fā)生事件的DOM元素對(duì)象
? ? ? ? ? ? <input onFocus={this.handleClick}/.>
????????????handleFocus(event) {?
?????????????????event.target //返回input對(duì)象
?????????????}
? ?????????注意 !!!!!!!!
? ? ? ????1). 組件內(nèi)置的方法中的this為組件對(duì)象
? ? ? ????2). 在組件中自定義的方法中的this為null
? ? ? ? ????* 強(qiáng)制綁定this(在construtor中綁定)
? ? ? ? ????* 箭頭函數(shù)(ES6模塊化編碼時(shí)才能使用)
? ???????? ??③ state 屬性(和 Vue 的data 相似)
? ? ? ? ? ? ? ? state 是 react 組件的初始數(shù)據(jù)
? ??????????????初始化狀態(tài):
? ? ? ????????constructor (props) {
? ? ? ? ? ? ? ????super(props);
? ? ? ?????????????this.state = {
? ? ? ? ? ????????stateProp1 : value1,
? ? ? ? ? ????????stateProp2 : value2
? ? ? ???????? ????};
? ? ????????? }
? ??????????????讀取數(shù)據(jù)狀態(tài)值
? ? ? ? ? ? ? ??? ???this.state.statePropertyName
? ??????????????更新狀態(tài)---->組件界面更新(不能使用this.state.statePropertyName = XXX捻撑;來設(shè)置值)
? ? ? ????????????this.setState({
? ? ? ? ????????????stateProp1 : value1,
? ? ? ? ????????????stateProp2 : value2
? ? ? ????????????})
????????????實(shí)現(xiàn)一個(gè)雙向綁定的組件
????????????????* React是單向數(shù)據(jù)流
????????????????* 需要通過onChange監(jiān)聽手動(dòng)實(shí)現(xiàn),更改state的值
? ? ? ? ? ? ? ? state 案例 TodoList
React 生命周期
? ? ?1).組件的三個(gè)生命周期狀態(tài):
? ? ????* Mount:將虛擬DOM 插入真實(shí) DOM(掛載)
? ? ????* Update:被重新渲染(更新)
? ? ????* Unmount:將虛擬DOM?移出真實(shí) DOM(卸載)
? ??2).?React 為每個(gè)狀態(tài)都提供了兩種勾子(hook)函數(shù)缤底,will 函數(shù)在進(jìn)入狀態(tài)之前調(diào)用顾患,did 函數(shù)在進(jìn)入狀態(tài)之后調(diào)用
? ? ????* componentWillMount( )
? ? ????* componentDidMount( ) : 已插入真實(shí)DOM, 在 render 之后才會(huì)執(zhí)行
? ????? * componentWillUpdate(object nextProps, object nextState)
? ? ????* componentDidUpdate(object prevProps, object prevState)
? ? ????* componentWillUnmount( )
?????3).生命周期流程:
? ? ????①. 第一次初始化渲染顯示: render( )
? ? ? ????* constructor( ): 創(chuàng)建對(duì)象初始化state
? ? ? ????* componentWillMount( ) : 將要插入回調(diào)
? ? ? ????* render( ) : 用于插入虛擬DOM回調(diào)
? ? ? ????* componentDidMount( ) : 已經(jīng)插入回調(diào)
? ? ? ? ②. 每次更新state: this.setSate( )
? ? ? ????* componentWillUpdate( ) : 將要更新回調(diào)
? ? ? ????* render( ) : 更新(重新渲染)
? ? ????? * componentDidUpdate( ) : 已經(jīng)更新回調(diào)
? ? ? ? ③. 刪除組件
? ? ? ????* ReactDOM.unmountComponentAtNode(document.getElementById('example')) : 移除組件
? ? ? ????* componentWillUnmount() : 組件將要被移除回調(diào)
? ??????注意:
? ? ????????* 一般會(huì)在componentDidMount()中: 開啟監(jiān)聽, 發(fā)送ajax請(qǐng)求
? ? ????????* 可以在componentWillUnmount()做一些收尾工作: 停止監(jiān)聽
? ? 條件渲染
? ? ? ? React 中的條件渲染? 和 Vue 中的 v-if = '' 相比,麻煩很多个唧。
? ??????React 中的條件渲染就和在 JavaScript 中的條件語句一樣江解。使用 JavaScript 操作符如 if 或者 條件操作符(如三元表達(dá)式,switch) 來創(chuàng)建渲染當(dāng)前狀態(tài)的元素徙歼,并且讓 React 更新匹配的 UI 犁河。
? ??????使用邏輯 && 操作符的內(nèi)聯(lián) if 用法
它可以正常運(yùn)行,因?yàn)樵?JavaScript 中魄梯,?true && expression?總是會(huì)評(píng)估為?expression?桨螺,而?false && expression?總是執(zhí)行為?false?。因此酿秸,如果條件為?true?灭翔,則?&&?后面的元素將顯示在輸出中。 如果是?false辣苏,React 將會(huì)忽略并跳過它肝箱。
? ? ? ? ? ? 就相當(dāng)于 JavaScript中的操作符運(yùn)算
? ? ? ? ? ? 還可以使用三元表達(dá)式? 例如:
? ??????????The user is <b>??{ isLoggedIn ? 'currently' : 'not' }? </b> logged in.
? ??????列表(Lists) 和 鍵(Keys)
? ? ? ? ? ? React 中的循環(huán)與 Vue 中的 v-for=' ' 相比 也比較復(fù)雜,但是它們都要在循環(huán)的元素標(biāo)簽上 加上?唯一的 key 值考润。
? ? ? ? ? ? 和 Vue 一樣狭园,鍵(Keys) 幫助 React 標(biāo)識(shí)哪個(gè)項(xiàng)被修改、添加或者移除了糊治。數(shù)組中的每一個(gè)元素都應(yīng)該有一個(gè)唯一不變的鍵(Keys)來標(biāo)識(shí)唱矛。不要用index !! 不要用index !! 不要用index !!
? ? ? ? ? ? 在React 中 使用 map()函數(shù)來遍歷/ 循環(huán)數(shù)組。
????????受控組件
? ? ? ? 在 HTML 中,表單元素如 <input>,<textarea>和 <select>表單元素通常保持自己的狀態(tài)绎谦,并根據(jù)用戶輸入進(jìn)行更新管闷。在 React 中,可變狀態(tài)一般保存在組件的 state(狀態(tài)) 屬性中窃肠,并且只能通過?setState()?更新包个。
????????我們可以通過使 React 的 state 成為 “單一數(shù)據(jù)源原則” 來結(jié)合這兩個(gè)形式。然后渲染表單的 React 組件也可以控制在用戶輸入之后的行為冤留。這種形式碧囊,其值由 React 控制的輸入表單元素稱為“受控組件”。
? ? ? ? ? ? 簡單的理解就是:將input中的value綁定到state的React組件就是可控組件纤怒,反之則是不可控組件糯而。
? ?????????? 受控組件的優(yōu)點(diǎn)
? ????????1. React是一個(gè)單向數(shù)據(jù)流,受控組件符合React單向數(shù)據(jù)流特性泊窘,即從state 流向 render輸出的結(jié)果熄驼。
? ????????2. 受控組件可以自定義雙向數(shù)據(jù)流組件。
? ? ? ? ? 3.數(shù)據(jù)存儲(chǔ)在state中烘豹,便于訪問和處理瓜贾。
? ??????????textare 標(biāo)簽 和?select 標(biāo)簽 的情況與 input 一樣 ,都是將便簽的 value 與 state 綁定携悯。
React 的編程思想
? ? ? ? ? ? ① 將 UI 拆解到組件層次結(jié)構(gòu)中
? ? ? ? ? ? ? ? 分析 UI設(shè)計(jì)圖祭芦,拆分組件
? ? ? ? ? ? ?但是你該如何拆分組件呢?其實(shí)只需要像拆分一個(gè)新方法或新對(duì)象一樣的方式即可憔鬼。一個(gè)常用的技巧是?單一職責(zé)原則实束,即一個(gè)組件理想情況下只處理一件事。如果一個(gè)組件持續(xù)膨脹逊彭,就應(yīng)該將其拆分為多個(gè)更小的組件中。
? ? ? ? ? ? ? ② 用 React 構(gòu)建一個(gè)靜態(tài)版本
? ??????????????????要構(gòu)建你 app 的一個(gè)靜態(tài)版本构订,用于渲染數(shù)據(jù)模型侮叮,?您將需要構(gòu)建復(fù)用其他組件并使用?props傳遞數(shù)據(jù)的組件。props?是將數(shù)據(jù)從 父級(jí)組件 傳遞到 子級(jí) 的一種方式悼瘾。如果你熟悉?state?的概念囊榜,在構(gòu)建靜態(tài)版本時(shí) *不要使用 *state?** 。state 只用于交互亥宿,也就是說卸勺,數(shù)據(jù)可以隨時(shí)被改變。由于這是一個(gè)靜態(tài)版本 app烫扼,所以你并不需要使用?state?曙求。
? ??????????????????可以 自上而下(構(gòu)建層次結(jié)構(gòu)中頂端的組件開始) 或 自下而上(構(gòu)建層次結(jié)構(gòu)中底層的組件) 構(gòu)建。在更簡單的例子中,通常 自上而下 更容易悟狱,而在較大的項(xiàng)目中静浴,自下而上,更有利于編寫測試挤渐。
? ? ? ? ? ? ? ③ 確定 UI state(狀態(tài)) 的最衅幌怼(但完整)表示
????????????????????????????要正確的構(gòu)建應(yīng)用程序,你首先需要考慮你的應(yīng)用程序需要的可變 state(狀態(tài)) 的最小集合浴麻。這里的關(guān)鍵是:不要重復(fù)你自己?(DRY得问,don’t repeat yourself)。找出你的應(yīng)用程序所需 state(狀態(tài)) 的絕對(duì)最小表示软免,并且可以以此計(jì)算出你所需的所有其他數(shù)據(jù)內(nèi)容宫纬。例如,如果你正在構(gòu)建一個(gè) TODO 列表或杠,只保留一個(gè) TODO 元素數(shù)組即可;不需要為元素?cái)?shù)量保留一個(gè)單獨(dú)的 state(狀態(tài)) 變量哪怔。相反,當(dāng)你要渲染 TODO 計(jì)數(shù)時(shí)向抢,只需要獲取 TODO 數(shù)組的長度即可认境。
? ? ? ? ? ? ? ④ 確定 state(狀態(tài)) 的位置
? ??????????????React 單向數(shù)據(jù)流在層級(jí)中?自上而下?進(jìn)行。這樣有可能不能立即判斷出狀態(tài)屬于哪個(gè)組件挟鸠。這常常是新手最難理解的一部分叉信,試著按下面的步驟分析操作:
????????????????對(duì)于你應(yīng)用中的每一個(gè) state(狀態(tài)) :
? ? ? ? ? ? ? ? 1).確定每個(gè)基于這個(gè) state(狀態(tài)) 渲染的組件。
????????????????2)找出公共父級(jí)組件(一個(gè)單獨(dú)的組件艘希,在組件層級(jí)中位于所有需要這個(gè) state(狀態(tài)) 的組件的上面)硼身。
????????????????3)公共父級(jí)組件 或者 另一個(gè)更高級(jí)組件擁有這個(gè) state(狀態(tài)) 。
? ? ? ? ? ? ? ? 4)如果找不出一個(gè)擁有該 state(狀態(tài)) 的合適組件覆享,可以創(chuàng)建一個(gè)簡單的新組件來保留這個(gè) state(狀態(tài)) 佳遂,并將其添加到公共父級(jí)組件的上層即可。
? ? ? ? ? ? ? ⑤?添加反向數(shù)據(jù)流
? ??????????????目前撒顿,構(gòu)建的應(yīng)用已經(jīng)具備了正確渲染 props(屬性) 和 state(狀態(tài)) 沿著層次結(jié)構(gòu)向下傳播的功能〕笞铮現(xiàn)在是時(shí)候?qū)崿F(xiàn)另一種數(shù)據(jù)流方式:層次結(jié)構(gòu)中深層的 form(表單) 組件需要更新中的 state(狀態(tài)) 。也就是將? input等 表單元素 中的value綁定到state 凤壁,我們可以使用 input 的 onChange 事件來接收通知吩屹,而且通過 傳遞的回調(diào)調(diào)用?setState(),然后應(yīng)用被更新拧抖。