React框架大筆記

React框架學習

React的起源和發展

起初facebook在建設instagram(圖片分享)的時候嘞,因為牽扯到一個東東叫數據流,那為了處理數據流并且還要考慮好性能方面的問題嘞,Facebook開始對市場上的各種前端MVC框架去進行一個研究,然而并沒有看上眼的,于是Facebook覺得,還是自己開發一個才是最棒的,那么他們決定拋開很多所謂的“最佳實踐”,重新思考前端界面的構建方式,他們就自己開發了一套,果然大牛創造力還是很強大的。

React的出發點

基于HTML的前端界面開發正變得越來越復雜,其本質問題基本都可以歸結于如何將來自于服務器端或者用戶輸入的動態數據高效的反映到復雜的用戶界面上(dom操作)。而來自Facebook的React框架正是完全面向此問題的一個解決方案,按官網描述,其出發點為:用于開發數據不斷變化的大型應用程序(Building large applications with data that changes over time)。相比傳統型的前端開發,React開辟了一個相當另類的途徑,實現了前端界面的 高性能 (減少dom操作 虛擬dom)高效率(組件開發模塊) 開發。

知乎 脈脈 it職場? 趣店? 滴滴

3年前端

14 html css? ajax? js jq? ? ? ios? 安卓? php? java? 手游藍海。。。 服務器渲染? 1階段? ie6的兼容問題

15 h5? 移動端? 響應式布局bootstrap? swiper 微場景? (angular 1.0)? ? ios? 安卓 php? java? 手游

16 前端工程化開發 剛剛開始興起? (angular vue? react)? ? ? ? ? ? ? 大前端? 微信小程序? 按照 php? java 手游 前端

17 前端框架大范圍的推廣 前端在開發中地位越來越高? 前后端分離? ? ? ? ? 大數據? 區款連? 人工智能ai

18 區款連? go? 前端框架大范圍的推廣快速的發展

React與傳統MVC的關系

輕量級的視圖層框架!

React不是一個完整的MVC框架,最多可以認為是MVC中的V(View),甚至React并不非常認可MVC開發模式;

React高性能的體現:虛擬DOM

React高性能的原理:

在Web開發中我們總需要將變化的數據實時反應到UI上,這時就需要對DOM進行操作。而復雜或頻繁的DOM操作通常是性能瓶頸產生的原因(如何進行高性能的復雜DOM操作通常是衡量一個前端開發人員技能的重要指標)。

React為此引入了虛擬DOM(Virtual DOM)的機制:在瀏覽器端用Javascript實現了一套DOM API。基于React進行開發時所有的DOM構造都是通過虛擬DOM進行,每當數據變化時,React都會重新構建整個DOM樹,然后React將當前整個DOM樹和上一次的DOM樹進行對比,得到DOM結構的區別,然后僅僅將需要變化的部分進行實際的瀏覽器DOM更新。而且React能夠批處理虛擬DOM的刷新,在一個事件循環(Event Loop)內的兩次數據變化會被合并,例如你連續的先將節點內容從A-B,B-A,React會認為A變成B,然后又從B變成A UI不發生任何變化,而如果通過手動控制,這種邏輯通常是極其復雜的。

盡管每一次都需要構造完整的虛擬DOM樹,但是因為虛擬DOM是內存數據,性能是極高的,部而對實際DOM進行操作的僅僅是Diff分,因而能達到提高性能的目的。這樣,在保證性能的同時,開發者將不再需要關注某個數據的變化如何更新到一個或多個具體的DOM元素,而只需要關心在任意一個數據狀態下,整個界面是如何Render的。數據驅動,聲明式

React的特點和優勢

虛擬DOM

我們以前操作dom的方式是通過document.getElementById()的方式,這樣的過程實際上是先去讀取html的dom結構,將結構轉換成變量,再進行操作

而reactjs定義了一套變量形式的dom模型,一切操作和換算直接在變量中,這樣減少了操作真實dom,性能真實相當的高,和主流MVC框架有本質的區別,并不和dom打交道

組件系統

react最核心的思想是將頁面中任何一個區域或者元素都可以看做一個組件 component

那么什么是組件呢?

組件指的就是同時包含了html、css、js、image元素的聚合體

使用react開發的核心就是將頁面拆分成若干個組件,并且react一個組件中同時耦合了css、js、image,這種模式整個顛覆了過去的傳統的方式

單向數據流

其實reactjs的核心內容就是數據綁定,所謂數據綁定指的是只要將一些服務端的數據和前端頁面綁定好,開發者只關注實現業務就行了

JSX 語法

在vue中,我們使用render函數來構建組件的dom結構性能較高,因為省去了查找和編譯模板的過程,但是在render中利用createElement創建結構的時候代碼可讀性較低,較為復雜,此時可以利用jsx語法來在render中創建dom,解決這個問題,但是前提是需要使用工具來編譯jsx 5. 官網?https://reactjs.org/?6. 主流的 hb wb atom sub vscode xcode nopad++

創建第一個組件

react開發需要引入多個依賴文件:react.js、react-dom.js,分別又有開發版本和生成版本

在這里一開始,我們先學習es5的組件寫法,React.createClass,需要引入的是15+

react.js中有React對象,幫助我們創建組件等功能

react-dom.js中有ReactDOM對象,渲染組件的虛擬dom為真實dom的爆發功能

在編寫react代碼的時候會大量的使用到jsx代碼,但是需要編譯:

瀏覽器端編譯,通過引入browser、babel等對引入的script內的代碼做編譯

利用webpack等開發環境進行編譯,將編譯好的文件引入到應用中

? ? //創建組件

? ? var Hello = React.createClass({

? ? ? ? render:function () {

? ? ? ? ? ? //render函數和Vue組件里的render完全一樣,在vue組件中可以不用編寫render函數,這個時候可以使用template模板來編寫組件的虛擬dom結構,然后vue組件會自動講模板compile成虛擬dom結構放入到render中執行,但是react需要編寫render函數

? ? ? ? ? ? return (

? ? ? ? ? ? ? ? //jsx語法

? ? ? ? ? ? ? ? <div>asdasd</div>

? ? ? ? ? ? )


? ? ? ? }

? ? })

? ? //利用ReactDOM對象的render方法將組件渲染到某個節點里

? ? ReactDOM.render(<Hello/>,document.getElementById("app"))

組件是通過React.createClass創建的(ES5),在es6中直接通過class關鍵字來創建

組件其實就是一個構造器,每次使用組件都相當于在實例化組件

react的組件必須使用render函數來創建組件的虛擬dom結構

組件需要使用ReactDOM.render方法將其掛載在某一個節點上

組件的首字母必須大寫

JSX語法糖

JSX是一種語法,全稱:javascript xml

JSX語法不是必須使用的,但是因為使用了JSX語法之后會降低我們的開發難度,故而這樣的語法又被成為語法糖

在不使用JSX的時候,需要使用React.createElement來創建組件的dom結構,但是這樣的寫法雖然不需要編譯,但是維護和開發的難度很高,且可讀性很差

var world = React.createElement('h1',{className:'abc',id:'haha'},[

? ? React.createElement('span',null,'Hello'),

? ? React.createElement('mark',null,'React')

])


//利用ReactDOM對象的render方法將組件渲染到某個節點里

ReactDOM.render(world,document.getElementById("app1"))

及時使用了JSX語法了之后,也是需要將其編譯成原生的createElement的

JSX就是在js中使用的xml,但是,這里的xml不是真正的xml,只能借鑒了一些xml的語法,例如:

最外層必須有根節點、標簽必須閉合

jsx借鑒xml的語法而不是html的語法原因:xml要比html嚴謹,編譯更方便

組件dom添加樣式

在react里表達式的符號是 "{ }",作用和vue的表達式作用是一樣的

想給虛擬dom添加行內樣式,需要使用表達式傳入樣式對象的方式來實現:

<p style = { {color:'red',fontSize:2+'em'} }>Hello world</p>

行內樣式需要寫入一個樣式對象,而這個樣式對象的位置可以放在很多地方,例如React.createClass的配置項中、render函數里、組件原型上、外鏈js文件中

React推薦我們使用行內樣式,因為react覺得每一個組件都是一個獨立的整體

其實我們大多數情況下還是大量的在為元素添加類名、id以使用某些樣式,但是需要注意的是,class需要寫成className(因為畢竟是在寫類js代碼,會收到js規則的現在,而class是關鍵字)

<p className="bg-p" id="myp" style = { this.style }>Hello world</p>

React Event

在react中,我們想要給組件的dom添加事件的話,也是 需要在行內添加的方式,事件名字需要寫成小駝峰的方式,值利用表達式傳入一個函數即可

注意,在沒有渲染的時候,頁面中沒有真實dom,所以是獲取不到dom的

給虛擬dom結構中的節點添加樣式。在行內添加,寫成駝峰形式,值是一個函數名,需要用{}包裹

handleClick:function () {

? ? alert(1)

},

render:function () {

? ? return (

? ? ? ? <div>

? ? ? ? ? ? <button onClick = {this.handleClick} className="click-btn">click</button>

? ? ? ? ? ? <button onDoubleClick = {this.handleClick} className="click-btn">click</button>

? ? ? ? </div>

? ? )

}

組件嵌套

將一個組件渲染到某一個節點里的時候,會將這個節點里原有內容覆蓋

組件嵌套的方式就是將子組件寫入到父組件的模板中去,且react沒有Vue中的內容分發機制(slot),所以我們在一個組件的模板中只能看到父子關系

var Hello = React.createClass({

? ? render(){

? ? ? ? return (

? ? ? ? ? ? <h1>

? ? ? ? ? ? ? ? Hello

? ? ? ? ? ? ? ? <World></World>

? ? ? ? ? ? </h1>

? ? ? ? )

? ? }

})

var World = React.createClass({

? ? render(){

? ? ? ? return (

? ? ? ? ? ? <mark>

? ? ? ? ? ? ? ? World-<Person/>

? ? ? ? ? ? </mark>

? ? ? ? )

? ? }

})

//無狀態組件

var Person =function(){

? ? return (<mark>lilei</mark>)

}

ReactDOM.render(<Hello/>,app)

注意,react中jsx里的注釋要寫成{/* */}的方式

React中的數據承載-Props/State

數據驅動、聲明式渲染:

任意的視圖變化都應該由數據來控制

//$(".a").html(0)

var num = 0 function renderNum () { $(".a").html(num) }

React也是基于數據驅動(聲明式)的框架,組件中必然需要承載一些數據,在react中起到這個作用的是屬性和狀態(props & state)

屬性(props) 在組件外部傳入,或者內部設置,組件內部通過this.props獲得

狀態(state) 在組件內部設置或者更改,組件內部通過this.state獲得

屬性(props)

屬性一般是外部傳入的,組件內部也可以通過一些方式來初始化的設置,屬性不能被組件自己更改

屬性是描述性質、特點的,組件自己不能隨意更改

使組件擁有屬性的方式:

在裝載(mount)組件的時候給組件傳入

傳入數據的時候,除了字符串類型,其他的都應該包上表達式,但是為了規整,所有的數據傳遞,最好都包上{}

var Gouzi = React.createClass({

? ? render(){

? ? ? ? console.log(this)

? ? ? ? return (

? ? ? ? ? ? <div>

? ? ? ? ? ? ? ? <p>我的名字:{this.props.name}</p>

? ? ? ? ? ? ? ? <p>我的性別:{this.props.sex}</p>

? ? ? ? ? ? ? ? <p>我的年齡:{this.props.age}</p>?

? ? ? ? ? ? ? ? <p>我的父親是:{this.props.father}</p>? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? </div>

? ? ? ? )

? ? }

})

let info = {

? ? sex:'male',

? ? father:'狗爸'

}

ReactDOM.render(<Gouzi {...info} name={"大狗子"} age={26}/>,app)

父組件給子組件傳入

父組件在嵌套子組件的時候為子組件傳入,傳入的方式和上面的方式一樣

//父組件的render函數

render(){

? ? return (

? ? ? ? <div>

? ? ? ? ? ? <p>父組件:</p>

? ? ? ? ? ? <hr/>

? ? ? ? ? ? <Son name={'大狗子'}/>

? ? ? ? ? ? <Son name={'二狗子'}/>

? ? ? ? </div>

? ? )

}

子組件自己設置

子組件可以通過getDefaultProps來設置默認的屬性

getDefaultProps的值是函數,這個函數會返回一個對象,我們在這里對象里為組件設置默認屬性

這種方式設置的屬性優先級低,會被外部傳入的屬性值所覆蓋

getDefaultProps:function () {

? ? console.log('getDefaultProps')

? ? return {

? ? ? ? name:'狗爸',

? ? ? ? sonname:'二狗子'

? ? }

},

//render

<p>我是{this.props.sonname}的父親-{this.props.name}</p>

根據屬性或狀態,我們可以在render中的表達式里做一些邏輯判斷,可以使用||、三元表達式、子執行函數等等

getName(){

? ? return this.props.name || '野狗子'

},

render:function () {

? ? let {name} = this.props

? ? return (

? ? <div>

? ? ? ? <p>我是子組件-{this.props.name || '野狗子'}</p>

? ? ? ? <p>我是子組件-{this.props.name?this.props.name:'野狗子'}</p>

? ? ? ? <p>我是子組件-{this.getName()}</p>

? ? ? ? <p>我是子組件-{(function (obj) {

? ? ? ? ? ? return obj.props.name || '野狗子'

? ? ? ? })(this)}</p>

? ? </div>

? ? )

}

狀態(state)

狀態就是組件描述某種顯示情況的數據,由組件自己設置和更改,也就是說由組件自己維護,使用狀態的目的就是為了在不同的狀態下使組件的顯示不同(自己管理)

在組件中只能通過getInitialState的鉤子函數來給組件掛載初始狀態,在組件內部通過this.state獲取

this.props和this.state是純js對象,在vue中,$data屬性是利用Object.defineProperty處理過的,更改$data的數據的時候會觸發數據的getter和setter,但是react中沒有做這樣的處理,如果直接更改的話,react是無法得知的,所以,需要使用特殊的更改狀態的方法:

setState(params)

在setState中傳入一個對象,就會將組件的狀態中鍵值對的部分更改,還可以傳入一個函數,這個回調函數必須返回像上面方式一樣的一個對象,函數可以接收prevState和props

//1.

let doing = this.state.doing=='學習'+props.knowledge?'玩游戲':'學習'+props.knowledge

this.setState({doing})

//2.

this.setState((prevState,props)=>{

? ? return {

? ? ? ? doing:prevState.doing=='學習'+props.knowledge?'玩游戲':'學習'+props.knowledge

? ? }

})

實現下拉菜單的方式

通過數據來控制元素的行內樣式中display的值,或者去控制類名

<ul style={{display:isMenuShow?'block':'none'}}><li>國內新聞</li></ul>

...

<ul className={isMenuShow?'show':'hide'}><li>國內新聞</li></ul>

根據數據控制是否渲染改節點、組件

{

? ? isMenuShow?<ul><li>國內新聞</li></ul>:''

}

通過ref對dom、組件進行標記,在組件內部通過this.refs獲取到之后,進行操作

<ul ref='content'><li>國內新聞</li></ul>

...

this.refs.content.style.display = this.state.isMenuShow?'block':'none'

屬性和狀態的對比

相似點:都是純js對象,都會觸發render更新,都具有確定性(狀態/屬性相同,結果相同)

不同點:

屬性能從父組件獲取,狀態不能

屬性可以由父組件修改,狀態不能

屬性能在內部設置默認值 ,狀態也可以

屬性不在組件內部修改 ,狀態要改

屬性能設置子組件初始值 ,狀態不可以

屬性可以修改子組件的值,狀態不可以

狀態只和自己相關,由自己維護

屬性不要自己修改,可以從父組件獲取,也可以給子組件設置

組件在運行時自己需要修改的數據其實就是狀態而已

組件的生命周期

react中組件也有生命周期,也就是說也有很多鉤子函數供我們使用,下面是生命周期的圖示:

組件是一個構造器,每一次使用組件都相當于在實例化組件,在這個時候,組件就會經歷一次生命周期,從實例化實例開始到這個實例銷毀的時候,都是一次完整的生命周期

組件的生命周期,我們會分為三個階段,初始化、運行中、銷毀

初始化階段

實例化組件之后,組件的getDefaultProps鉤子函數會執行

這個鉤子函數的目的是為組件的實例掛載默認的屬性

這個鉤子函數只會執行一次,也就是說,只在第一次實例化的時候執行,創建出所有實例共享的默認屬性,后面再實例化的時候,不會執行getDefaultProps,直接使用已有的共享的默認屬性

理論上來說,寫成函數返回對象的方式,是為了防止實例共享,但是react專門為了讓實例共享,只能讓這個函數只執行一次

組件間共享默認屬性會減少內存空間的浪費,而且也不需要擔心某一個實例更改屬性后其他的實例也會更改的問題,因為組件不能自己更改屬性,而且默認屬性的優先級低。

執行getInitialState為實例掛載初始狀態,且每次實例化都會執行,也就是說,每一個組件實例都擁有自己獨立的狀態呢

執行componentWillMount,相當于Vue里的created+beforeMount,這里是在渲染之前最后一次更改數據的機會,在這里更改的話是不會觸發render的重新執行

多做一些初始數據的獲取

執行render,渲染dom

執行componentDidMount ,相當于Vue里的mounted,多用于操作真實dom

運行中階段

當組件mount到頁面中之后,就進入了運行中階段,在這里有5個鉤子函數,但是這5個函數只有在數據(屬性、狀態)發送改變的時候才會執行

componentWillReceiveProps

當父組件給子組件傳入的屬性改變的時候,子組件的這個函數才會執行

當執行的時候,函數接收的參數是子組件接收到的新參數,這個時候,新參數還沒有同步到this.props上,多用于判斷新屬性和原有屬性的變化后更改組件的狀態

接下來就會執行shouldComponentUpdate,這個函數的作用:

當屬性或狀態發送改變后控制組件是否要更新,提高性能,返回true就更新,否則不更新,默認返回true

接收nextProp、nextState,根據根據新屬性狀態和原屬性狀態作出對比、判斷后控制是否更新

componentWillUpdate,在這里,組件馬上就要重新render了,多做一些準備工作,千萬千萬,不要在這里修改狀態,否則會死循環 相當于Vue中的beforeUpdate

render,重新渲染dom

componentDidUpdate,在這里,新的dom結構已經誕生了,相當于Vue里的updated

銷毀階段

當組件被銷毀之前的一剎那,會觸發componentWillUnmount,臨死前的掙扎

相當于Vue里的beforeDestroy,所以說一般會做一些擦屁股的事情

為什么Vue中有destroyed,而react卻沒有componentDidUnmount

Vue在調用$destroy方法的時候就會執行beforeDestroy,然后組件被銷毀,這個時候組件的dom結構還存在于頁面結構中,也就說如果想要對殘留的dom結構進行處理必須在destroyed處理,但是react執行完componentWillUnmount之后把事件、數據、dom都全部處理掉了,所以根本不需要其他的鉤子函數了

怎么樣就算組件被銷毀:

當父組件從渲染這個子組件變成不渲染這個子組件的時候,子組件相當于被銷毀

調用ReactDOM.unmountComponentAtNode(node) 方法來將某節點中的組件銷毀

React中的事件對象

react中對于事件進行了處理,解決了一些兼容性問題,react事件對象上面掛載著nativeEvent,這個就是原生的事件對象

react對事件對象做了優化,如果不取值的話,值都是null

React中組件通信方式

父組件與子組件通信

父組件將自己的狀態傳遞給子組件,子組件當做屬性來接收,當父組件更改自己狀態的時候,子組件接收到的屬性就會發生改變

父組件利用ref對子組件做標記,通過調用子組件的方法以更改子組件的狀態,也可以調用子組件的方法..

子組件與父組件通信

父組件將自己的某個方法傳遞給子組件,在方法里可以做任意操作,比如可以更改狀態,子組件通過this.props接收到父組件的方法后調用。

兄弟組件通信

在react沒有類似vue中的事件總線來解決這個問題,我們只能借助它們共同的父級組件來實現,將非父子關系裝換成多維度的父子關系

復雜的非父子組件通信在react中很難處理,多組件間的數據共享也不好處理,所以我們會使用flux、redux來實現這樣的功能,解決這個問題

React中表單元素默認值

在react中,如果需要 給表單元素設置默認value或者checked,需要設置成defaultValue/defaultChecked,否則設置默認值以后,用戶無法更改

React中的mixins

在vue中我們可以將一些通用的、公用的方法放入到某一個純js對象中,然后,在需要使用改方法的組件中使用mixins配置(值為對象)將該js對象中的方法注入到組件中,這樣就能實現代碼復用,便于維護

在React中曾經也有這樣的api,但是在高版本react中推薦我們使用es6中的class來創建組件了,這個時候無法使用mixinsapi,所以mixins被廢棄了,如果要使用公用代碼抽離,我們可以使用模塊化

React-keys

我們在react中循環列表數據的時候,需要對循環出來的虛擬jsx節點傳入上key這個數據,

Keys可以在DOM中的某些元素被增加或刪除的時候幫助React識別哪些元素發生了變化。因此你應當給數組中的每一個元素賦予一個確定的標識。

狀態提升

就是如果有多個組件共享一個數據,把這個數據放到共同的父級組件中來管理

組合

在vue中有一個內容分發叫slot,在react中也有實現,就是可以在使用組件的時候,在組件標簽內部放入一些不固定的內容,在該組件的模板中,只有{this.props.children}來表示

//App

<Dialog

close={this.ToggleDialogShow} isShow={isDialogShow}

>

? ? <ContentA/>

? ? <ContentA/>

? ? <ContentB/>

</Dialog>

//dialog

<div style={{display:isShow?'block':'none'}} className="dialog">

? ? <Button handler={this.props.close} text="關閉"/>?

? ? {this.props.children}//這里就是slot

</div>

webpack

前端工程化: npm、cnpm、yarn、bower | grunt 、 gulp 、webpack

gulp: 基于流的前端自動化構建工具,基于流的任務式的工具

webpack: 是一款模塊化打包工具,webpack是基于配置的,通過配置一些選項來讓webpack執行打包任務。

npm i webpack -g

npm i webpack-cli -g (4.0+)

npm i yarn -g

webpack在打包的時候,依靠依賴關系圖,在打包的時候需要告知webpack兩個概念:入口和出口

一般情況下,我們需要使用webpack.config.js進行配置

entry

entry配置項目打包的入口,值可以為單個的字符串執行某一個文件的地址,這個時候該文件就是入口文件,webpack會根據入口文件里各模塊間的關系形成依賴關系圖,然后根據依賴關系圖進行打包

entry:'./src/app.js',

output:{

? ? path:path.join(__dirname,'build'),

? ? filename:'app.js'

}

但是有的時候我們需要的是多入口,我們就寫成數組的形式,數組里的每一個字符串地址指向的都是一個獨立的入口,webpack會將這些入口的依賴打包

entry:['./src/app.js','./src/vendor.js'],

output:{

? ? path:path.join(__dirname,'build'),

? ? filename:'[name].js'//不確定名字的時候,這里會打包成main.js

}

剛才的兩種entry配置都只會打包出一個js文件,但是在某一個應用中我們可能需要將js根據依賴關系打包成多個js文件,并且在多頁面應用中,我們也確實不可能只使用一個js文件,那么我們就可以使用如下的配置:

? ? entry:{

? ? ? ? app:'./src/app.js',

? ? ? ? vendor:'./src/vendor.js'

? ? },

? ? output:{

? ? ? ? path:path.join(__dirname,'build'),

? ? ? ? filename:'[name]_[hash].js'

? ? }

這樣,因為filename里寫成名字是[name],所以會根據entry的配置的鍵名來為打包出的js文件命名,hash是每次打包的一個隨機的hash值,可以用來做版本控制

output

在這里我們配置打包輸出的一些選項

filename可以確定打包出來的文件的名字,在里面我們可以使用[name],[hash]這樣的占位符

path配置打包出去的文件的路徑,需要是絕對路徑

env

在命令行或者終端中執行 webpack --env hello命令,就相當于在打包的時候傳入一個參數為hello

在webpack.config.js中可以暴露出一個函數,這個函數就可以接收到env參數,當然函數就可以根據env參數來有選擇的返回某一個或多個配置對象

module.exports = (env)=>{

? ? if(env=='production'){

? ? ? ? return productionConfig

? ? }

? ? return developmentConfig

}

--watch 可以讓webpack去監聽文件的改變。 可以在package.json里的scripts中配置一些快捷操作,通過npm run來運行

plugins

在webpack編譯用的是loader,但是有一些loader無法完成的任務,交由插件(plugin)來完成,插件的時候需要在配置項中配置plugins選項,值是數組,可以放入多個插件的使用,而一般的插件都是一個構造器,我們只需在plugins數組中放入該插件的實例即可,在實例化插件的時候又可以傳入options,對插件的使用進行配置

html-webpack-plugin

這個插件可以選擇是否依據模板來生成一個打包好的html文件,在里面可以配置、title、template、filename、minify等選項,詳情請查閱文檔

在這個插件里,我們可以使用jade、hbs、ejs等模板引擎來編譯成html,這里舉例jade的配置:

文檔

npm i jade jade-loader --save-dev

module:{

? ? rules:[

? ? ? ? {

? ? ? ? ? ? test:/\.jade$/,

? ? ? ? ? ? use:'jade-loader'

? ? ? ? }

? ? ]

},

plugins:[

? ? new HtmlWebpackPlugin({

? ? ? ? // title:'webpack-config-demo',

? ? ? ? template:'./src/index.jade',

? ? ? ? filename:'index.html'

? ? })

]

webpack-dev-server

webpack相輔相成的有一個server功能工具可以提供開發的熱更新服務器

npm install webpack-dev-server -g npm install webpack-dev-server -D

第一種啟動方式: 直接執行webpack-dev-server,如果有需要配置的選項,在后面跟上參數即可。例如

webpack-dev-server --hot true

第二種啟動方式:在webpack.config.js中配置devServer的選項,執行webpack-dev-server就ok

devServer:{

? ? port:9000,

? ? contentBase:'./build',

? ? historyApiFallback: true,

? ? open: true,

? ? proxy:{


? ? }

}

LOADERS

在webpack中專門有一些東西用來編譯文件、處理文件,這些東西就叫loader,loader的使用就是在配置項中,設置modules,在modules中設置rule值為數組,在數組里放入多個匹配規則:

module:{

? ? rules:[

? ? ? ? {test:/\.css$/,use:'css-loader'}

? ? ],

? ? //before

? ? loaders:[

? ? ? ? {test:/\.css$/,loader:'css-loader'}

? ? ],

}

test為此次匹配要匹配的文件正則規則,use代表要使用的loader

使用url-loader可以將css中引入的圖片(背景圖)、js中生成的img圖片處理一下,生成到打包目錄里

視圖html-withimg-loader可以將html中img標簽引入的img圖片打包到打包目錄

file-loader

{

? ? test:/\.(png|jpe?g|svg|gif)$/,

? ? // use:'url-loader?limit=1000&name=images/[hash:8].[name].[ext]'

? ? use:[

? ? ? ? {

? ? ? ? ? ? loader:'url-loader',

? ? ? ? ? ? options:{

? ? ? ? ? ? ? ? limit:1000,

? ? ? ? ? ? ? ? name:'/static/images/assets/[hash:8].[name].[ext]'

? ? ? ? ? ? }

? ? ? ? }

? ? ]

},

{

? ? test:/\.html$/,

? ? use:'html-withimg-loader'

}

處理css:

cnpm i css-loader style-loader --save-dev

配置:

{ test:/.css$/, use:['style-loader','css-loader'] }

注意。webpack中loader的使用是從后往前的

css-loader可以將引入到js中的css代碼給抽離出來,style-loader可以將抽離出來的css代碼放入到style標簽中

處理sass

{ test:/.scss$/, use:['style-loader','css-loader','sass-loader'] },

將引入項目的css文件、scss文件抽成一個文件,引入到頁面中

cnpm i extract-text-webpack-plugin

const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')

///loader

{

test:/\.css$/,

use:ExtractTextWebpackPlugin.extract({

? ? ? fallback: "style-loader",

? ? ? use: "css-loader"

? ? })

},

{

test:/\.scss/,

use:ExtractTextWebpackPlugin.extract({

? ? ? fallback: "style-loader",

? ? ? use: ["css-loader","sass-loader"]

? ? })

}

///plugin

new ExtractTextWebpackPlugin({

filename:'app.css',

allChunks:true

})

因為ExtractTextWebpackPlugin對webpack4支持的不是很好,所以我們這樣解決:

cnpm i extract-text-webpack-plugin@next -D yarn add extract-text-webpack-plugin@next -D

@next下載的就是最最新的版本,可能是開發版本

webpack-dev-server進行了一個優化,在跑起服務的時候,會將編譯結果保存在內存里,不會實時的輸出的打包結果

css兼容優化處理:post-css 、autoprefixer

處理es6:

需要的依賴:

"babel": "^6.23.0", "babel-core": "^6.24.1", "babel-loader": "^7.0.0", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1",

rules: { test:/.js$/, exclude: /node_modules/, loader:'babel-loader', query: { presets: ['es2015','react'] } }

ES6中的react

1.創建組件:

使用class來創建組件

class App extends React.Component {

}

2.默認狀態的設置

在es6中不再使用getInitialState來設置默認狀態,而是在constructor里面直接給this.state上掛載狀態

class App extends Component { constructor(props){ super(props)

this.state={

doing:'吃飯'

}

}

}

默認屬性的設置

在es6中,通過給類設置defaultProps屬性來設置默認屬性

App.defaultProps = { name:'App根組件' }

做屬性傳參驗證

import PropTypes from 'prop-types';

App.propTypes = { name:PropTypes.string }

5.鉤子函數有變化

getDefaultProps、getInitialState沒有了

多出了constructor,而這個函數本身是類的構造器,在這里相當于getDefaultProps、getInitialState的結合

create-react-app 腳手架

npm install creat-react-app -g

create-react-app my-app //生成一個react開發模板在my-app目錄 //生成的過程特別緩慢,可以使用yarn工具來下載,也就是說先去下載安裝yarn :npm install yarn -g

當我們要進行二次配置的時候,需要找到node_modules文件夾里的react-scripts進行配置,但是當我們執行npm run eject就可以將配置文件抽出,方便開發配置

無狀態組件

當我們使用某些組件的時候,發現,該組件不需要擁有自己的狀態,只需要接收到外界傳入的屬性之后做出相應的反應即可

這樣的話,我們可以利用純函數的方式將其制作成無狀態組件,提高性能

import React from 'react'

const Button = (props)=>{

return <button onClick={props.handler}>我要花錢</button>

}

export default Button

Flux

在2014年,facebook提出了Flux,Flux 是一種架構思想,專門解決軟件的結構問題。它跟MVC 架構是同一類東西,但是更加簡單和清晰。

其實FLUX在react里的應用就類似于vue中的vuex的作用,但是

在vue中,vue是完整的mvvm框架,而vuex只是一個全局的插件

react只是一個視圖層的框架,在flux是一個架構思想,我們在做項目的時候使用flux架構的話要比單純使用react要簡單很多,這個時候,react在整個FLUX架構中擔任某一個角色的

react在這里只是充當了FLUX架構體系中的view層

Flux的組成部分:

View: 視圖層

ActionCreator(動作創造者):視圖層發出的消息(比如mouseClick)

Dispatcher(派發器):用來接收Actions、執行回調函數

Store(數據層):用來存放應用的狀態,一旦發生變動,就提醒Views要更新頁面

Flux的流程:

組件獲取到store中保存的數據掛載在自己的狀態上

用戶產生了操作,調用actions的方法

actions接收到了用戶的操作,進行一系列的邏輯代碼、異步操作

然后actions會創建出對應的action,action帶有標識性的屬性

actions調用dispatcher的dispatch方法將action傳遞給dispatcher

dispatcher接收到action并根據標識信息判斷之后,調用store的更改數據的方法

store的方法被調用后,更改狀態,并觸發自己的某一個事件

store更改狀態后事件被觸發,該事件的處理程序會通知view去獲取最新的數據

redux

React 只是 DOM 的一個抽象層,并不是 Web 應用的完整解決方案。有兩個方面,它沒涉及。

代碼結構

組件之間的通信

2014年 Facebook 提出了 Flux 架構的概念,引發了很多的實現。2015年,Redux 出現,將 Flux 與函數式編程結合一起,很短時間內就成為了最熱門的前端架構。

如果你不知道是否需要 Redux,那就是不需要它

只有遇到 React 實在解決不了的問題,你才需要 Redux

簡單說,如果你的UI層非常簡單,沒有很多互動,Redux 就是不必要的,用了反而增加復雜性。

用戶的使用方式非常簡單

用戶之間沒有協作

不需要與服務器大量交互,也沒有使用 WebSocket

視圖層(View)只從單一來源獲取數據

需要使用redux的項目:

用戶的使用方式復雜

不同身份的用戶有不同的使用方式(比如普通用戶和管理員)

多個用戶之間可以協作

與服務器大量交互,或者使用了WebSocket

View要從多個來源獲取數據

從組件層面考慮,什么樣子的需要redux:

某個組件的狀態,需要共享

某個狀態需要在任何地方都可以拿到

一個組件需要改變全局狀態

一個組件需要改變另一個組件的狀態

redux的設計思想:

Web 應用是一個狀態機,視圖與狀態是一一對應的。

所有的狀態,保存在一個對象里面(唯一數據源)。

redux的流程:

1.store通過reducer創建了初始狀態 2.view通過store.getState()獲取到了store中保存的state掛載在了自己的狀態上 3.用戶產生了操作,調用了actions 的方法 4.actions的方法被調用,創建了帶有標示性信息的action 5.actions將action通過調用store.dispatch方法發送到了reducer中 6.reducer接收到action并根據標識信息判斷之后返回了新的state 7.store的state被reducer更改為新state的時候,store.subscribe方法里的回調函數會執行,此時就可以通知view去重新獲取state

注意:flux、redux都不是必須和react搭配使用的,因為flux和redux是完整的架構,在學習react的時候,只是將react的組件作為redux中的視圖層去使用了。

reducer必須是一個純函數:

Reducer 函數最重要的特征是,它是一個純函數。也就是說,只要是同樣的輸入,必定得到同樣的輸出。

純函數是函數式編程的概念,必須遵守以下一些約束。

不得改寫參數

不能調用系統 I/O 的API

不能調用Date.now()或者Math.random()等不純的方法,因為每次會得到不一樣的結果

由于 Reducer 是純函數,就可以保證同樣的State,必定得到同樣的 View。但也正因為這一點,Reducer 函數里面不能改變 State,必須返回一個全新的對象,請參考下面的寫法。

// State 是一個對象

function reducer(state, action) {

? return Object.assign({}, state, { thingToChange });

? // 或者

? return { ...state, ...newState };

}

// State 是一個數組

function reducer(state, action) {

? return [...state, newItem];

}

最好把 State 對象設成只讀。你沒法改變它,要得到新的 State,唯一辦法就是生成一個新對象。這樣的好處是,任何時候,與某個 View 對應的 State 總是一個不變的對象。

我們可以通過在createStore中傳入第二個參數來設置默認的state,但是這種形式只適合于只有一個reducer的時候

劃分reducer

因為一個應用中只能有一個大的state,這樣的話reducer中的代碼將會特別特別的多,那么就可以使用combineReducers方法將已經分開的reducer合并到一起

注意:

分離reducer的時候,每一個reducer維護的狀態都應該不同

通過store.getState獲取到的數據也是會安裝reducers去劃分的

劃分多個reducer的時候,默認狀態只能創建在reducer中,因為劃分reducer的目的,就是為了讓每一個reducer都去獨立管理一部分狀態

React-router

市場上的react-router的版本有1、2、3、4,1-3的差別不大,使用于16.0.0以下的版本

react-router 4.0 適用于16.0.0以上

在這里使用15.6.1的react。這個版本的react允許使用React.createClass來創建組件,在16以上只能使用class類的方式來創建

渲染根組件的時候,最外層包裹上Router組件,在其上可以設置history屬性,值可以是hashHistory||browserHistory

當值為hashHistory的時候,url的變化為hash值的變化,router會去檢測hash變化來實現組件的切換

當值為browserHistory的時候,url的變化為path的變化,需要后端進行配置

Router中使用Route組件來描述每一級路由,Route上有path、component屬性,代表著當path改變成...的時候,就渲染..組件

在需要切換路由組件的地方,通過this.props.children來表示對應路由組件

在Route中可以多次嵌套Route來實現多級路由

IndexRoute可以設置該路由中的默認子路由

IndexRedirect可以設置在進入該路由之后馬上跳轉到哪里

使用Redirect組件可以做到從一個路由馬上重定向到其他路由,利用這樣的屬性,當我們form設置為'*'的時候,就可以將匹配不到的路由重定向到某げ路由下

可以在配置Route的時候給path里加入/:param 才表示此路由需要參數

傳入的時候,querystring參數可以在Link里的query中傳入和設置,在目標組件中,通過this.props中的,params、routePrams、location等來接收參數

可以通過過Router傳入routes參數,值為數組,來設置路由配置:

const routeConfig = [

? { path: '/',

? ? component: App,

? ? indexRoute: { component: Home },

? ? childRoutes: [

? ? ? { path: 'home', component: Home },

? ? ? { path: 'news',

? ? ? ? component: News,

? ? ? ? childRoutes: [

? ? ? ? ? { path: 'inside', component: Inside },

? ? ? ? ? { path: 'outside',component:Outside}

? ? ? ? ]

? ? ? },

? ? ? { path: 'detail/:id', component: Detail },

? ? ? {path:'*',component:Home}

? ? ]

? }

]

ReactDOM.render(

<Router routes={routeConfig} history={hashHistory}></Router>

,document.getElementById('app'))

編程式導航

在路由組件中通過this.props.history獲取到history對象,利用里面push、replace、go、goBack方法來進行隱式跳轉

可以從react-router中引入browserHistory或者hashHistory調用里面的push、replace、go、goBack方法來進行隱式跳轉

可以通過在路由配置上設置 onLeave和onEnter路由鉤子來監聽路由的變化

UI組件庫

關于React的UI組件庫市場上也有很多,在這里我們使用螞蟻金服開發的AntDesign組件庫

這是PC端的,移動端的是Antd-Mobile

React-redux

這個庫或者說工具是redux的開發者專門為react創建出來的,為我們在react中使用redux提供便利

起到的是橋梁的作用,能將react和redux更好的連接在一起

React-Redux 將所有組件分成兩大類:UI 組件/木偶組件(presentational component)和容器組件/智能組件(container component)。

UI 組件有以下幾個特征。

只負責 UI 的呈現,不帶有任何業務邏輯

沒有狀態(即不使用this.state這個變量)

所有數據都由參數(this.props)提供

不使用任何 Redux 的 API

容器組件的特征恰恰相反。

負責管理數據和業務邏輯,不負責 UI 的呈現

帶有內部狀態

使用 Redux 的 API

只要記住一句話就可以了:UI 組件負責 UI 的呈現,容器組件負責管理數據和邏輯。

你可能會問,如果一個組件既有 UI 又有業務邏輯,那怎么辦?回答是,將它拆分成下面的結構:外面是一個容器組件,里面包了一個UI 組件。前者負責與外部的通信,將數據傳給后者,由后者渲染出視圖。

React-Redux 規定,所有的 UI 組件都由用戶提供,容器組件則是由 React-Redux 自動生成。也就是說,用戶負責視覺層,狀態管理則是全部交給它。

使用方法及步驟:

使用Provider組件,包裹在應用的最外層,并為Provider注入store屬性,此時,Provider就會將自己的store屬性傳遞給子組件組合中的容器組件

使用connect函數,可以根據一個現有的UI組件生成一個容器組件,且我們在使用的時候,其實一直在使用的都是容器組件,connect函數執行之后返回一個函數,將返回的函數傳入UI組件并執行之后就會生成一個容器組件

connect函數有兩個參數:mapStateToProps,mapDispatchToProps

mapStateToProps的作用很簡單,就是將redux中的state傳遞到UI組件的props上,此參數是一個函數,接收到store的state然后再返回一個對象,返回的對象中的屬性就會傳遞到UI組件的屬性上

mapStateToProps對store進行了訂閱,只要state更改,mapStateToProps會自動執行并獲取到最新的state傳入到UI組件的屬性上

mapDispatchToprops 函數,接收到dispatch參數,其實就是store.dispatch,返回的對象中設置的方法可以使用到dispatch,且能傳入到UI組件的屬性上

那么,有了mapDistpatchToProps之后,我們就不需要actions了嗎?

我們需要將一些復雜的業務邏輯,或者說異步的業務邏輯抽離出來放入到actions里面去,也就是后所mapDispatchToProps里自己創建的只是一些簡單的方法就可以了

第一次使用react-redux等工具的做法

創建了actionCreator,專門生成action,又設置 了actions,在actions里放一些異步的、復雜的操作之后,調用actionCreator生成action再dispatch到reducer

其實我們上面創建actions的目的,就是因為ActionCreator不能做復雜的動作,其實我們可以使用redux-thunk來對reducer創建中間件,讓actionCreator的方法能返回一個函數,這個函數就可以接收到dispatch,且做出異步操作之后dispatch出action,也就是說,我們不需要再創建actions來分離異步復雜操作,而且直接可以在ActionCreator里寫異步方法

步驟:

對store中的reducer使用redux-thunk

import {createStore,applyMiddleware} from 'redux'

import reducer from './reducer'

import thunk from 'redux-thunk'

const store = createStore(reducer,applyMiddleware(thunk))

export default store

在ActionCreator的方法中返回方法來做異步處理

const actions_thunk = {

clearCart(){

//做異步操作之后生成action且dispatch

return (dispatch)=>{

setTimeout(function(){

localStorage.removeItem('cars')

let action = change_cars([])

dispatch(action)

},500)

}

}

}

可以將actionCreator的方法利用bindActionCreator放入到mapDispatchToProps中

import {bindActionCreators} from 'redux'

import actions_thunk from '../../redux/ActionCreators/actions_thunk'

export default connect(state=>state,dispatch=>{

return {

actions_thunk:bindActionCreators(actions_thunk,dispatch)

}

})(ClearCar)

///

button onClick={this.props.actions_thunk.clearCart}

其實,現在有這樣的流行做法:

將所有的數據都交由redux管理,這樣的話,我們的組件在UI層的邏輯就更純粹了,而且可以做到數據緩存,比如,A組件獲取了數據放入到redux中,當A組件被切換掉之后重新切換回來的時候,數據依然在redux中可以找到,也就是說直接取出來用就ok,不需要重新獲取

React 擴展

ref推薦使用函數的方法:

字符串方式

<Son ref="son"></Son>

//

this.refs.son

函數方式(推薦)

<Son ref={(el)=>{this.son = el}}></Son>

//

this.son

考試題:

react的特點不包括什么?

聲明式設計、高效、靈活、(雙向數據流)

動畫可以使用哪個第三方插件實現:

(ReactTransitionGroup)/animate.css/transitionTranslate/redux-thunk

ReactRouter中,路由的onLeave應該寫在哪里:

路由對應的組件中、父組件中、(路由組件中)、最外層大組件中

react-redux中的connect方法的返回值是一個: ContainerComponent = connect()(UIComponent) 對象、(容器組件)、UI組件、數組

react中常提到的中間件的概念,指的是:

react中間件、flux中間件、(redux中間件)、react-redux中間件

redux設計的三大原則:

(store唯一/唯一數據源、 state只讀、 reducer是純函數) reducer只讀

哪些不是react-router的組件:

(Provider)、Route、Router、(MapStateToProps)

下面哪些方法可以使componentWillUpdate執行

屬性更改或者狀態更改

請簡述對虛擬dom的理解,為什么使用虛擬DOM可以極大的提升react的性能

虛擬dom是真實dom的js對象映射,使用虛擬dom,避免對原生dom的創建和比對,取而代之的創建和比對的是js對象

原生dom的創建和比對是非常消耗性能的,而js對象的對比和創建對性能開銷很小,從這種方式來提供應用的性能

請說明在react中ref的作用,并寫出使用ref的兩種方式,說明哪一種是官方推薦的

ref可以使我們在react對dom或者子組件做出標記并獲取:

//this.refs.son <Son ref={(el)=>{this.son = el}}>//this.son(官方推薦)

說明react中,父子組件項目傳值的方式,并說明在大型項目中為什么要引入flux或者redux這種開發架構 父組件將自己的狀態當成屬性傳遞給子組件 父組件將自己的方法傳遞給子組件,子組件在調用的時候傳參 父組件通過ref獲取到子組件,調用子組件的方法傳參

react是一款視圖層的輕量級前端框架,大量的非父子組件通信、狀態共享會導致整個項目數據復雜,難以維護,所以react不適合處理大量的數據通信,為了解決這個問題,引入了FLUX、REDUX這樣的數據架構,react結合FLUX或者redux才能實現比較復雜的前端項目

在react中,列表循環盡量不要使用index作為key值,這和diff算法有關系,請簡述diff算法中key值有什么作用,為什么key中使用index值會降低代碼性能

key值是diff算法中對比兩個虛擬dom的最重要參考,決定了哪些列表中的組件可以復用,如果使用index作為key中,列表數據改變后,會導致同一個dom元素的key中發送改變,本來可以復用的組件必須重新創建,降低頁面性能,除非列表不需要改變,一般情況不使用index作為key值

請列舉你所了解的react中的性能優化

沒必要存在store中的數據,存在state中就可以

函數的this執行放在constructor中改變

和頁面顯示無關的數據不要放在state中

shouldComponentUpdate來判斷組件是否需要重新render(使用pureComponent)

使用性能分析工具進行性能分析,找問題解決問題

13.1 pureComponnet pureComponnet里如果接收到的新屬性或者是更改后的狀態和原屬性、原狀態相同想等的話,就不會去重新render了 在里面也可以使用shouldComponentUpdate,而且。是否重新渲染以shouldComponentUpdate的返回值為最終的決定因素 class ABC extends pureComponnet {

}

請說明react中引入redux-thunk、redux-promise這兩種中間件可以解決什么樣的問題

通常情況下,action只是一個對象,不能包含異步操作,這導致了很多創建action的邏輯只能寫在組件中,代碼量較多也不便于復用,同時對該部分代碼測試的時候也比較困難,組件的業務邏輯也不清晰,使用中間件了之后,可以通過actionCreator異步編寫action,這樣代碼就會拆分到actionCreator中,可維護性大大提高,可以方便于測試、復用,同時actionCreator還集成了異步操作中不同的action派發機制,減少編碼過程中的代碼量

畫圖說明redux的架構,寫出redux中常用的函數

dispatch , subscribe,combineReducers,getState,createStore

簡述react-redux結合react-router在項目中的使用方式

創建store,編寫reducer

在外面嵌套,將store傳遞給各個子組件

編寫UI組件

使用react-redux的connect方法結合mapStateToProps、mapDispatchToProps生成容器組件,容器組件和store連接在一起

router4

創建store,編寫reducer

在外面嵌套,將store傳遞給各個子組件

編寫UI組件

使用react-redux的connect方法結合mapStateToProps、mapDispatchToProps生成容器組件,容器組件和store連接在一起

如果某一個組件不是路由組件,卻需要使用router相關api,并且還需要使用store中的state的時候,需要在最外層包裹withRouter,里面再使用connect生成容器組件

下列說法錯誤的是:

(React是一款專注于數據層的前端框架)、react中需要調用setState方法來重置狀態、react中的虛擬dom可以提升框架自身的性能、(react是一款符合MVVM設計思想的前端框架)

關于前端組件化說法錯誤的是:

前端組件使得復雜的代碼得以被更好的劃分、組件化的代碼設計方式增加了代碼的可復用性、(在拆分組件的時候將組件拆分的越小越細越好)、組件化開發是一種設計思想,不是react獨享的

在react中,異步獲取ajax數據一般放在那個生命周期函數:componentWillMount

使用es6定義組件,可以在那個生命周期鉤子函數里使用this.state=state 對state進行賦值。而不需要調用this.setState方法:constructor

在redux中,重要的組成部分不包括:

store、action、reducer、(dispatcher)

webpack中html-webpack-plugin插件可以完成的任務是:

(在打包輸出目錄中自動生成index.html)、(向打包目錄中的index.html文件內插入打包生成的js文件引用)、將js源碼中引用的css代碼抽離ちゅ單獨的css文件并放置到打包輸出目錄、(像打包輸出目錄中的index.html文件插入打包生成的css引用)

關于jsx,說明正確的是:(ad)

a:jsx中可以通過{}來使用js的表達式,b:jsx中可以通過{}來使用js的代碼,c:jsx中可以使用style={color:'red'}來設置元素的樣式、d:jsx代碼會被解析成一個js對象

react組件被掛載到頁面 的時候,被執行的生命周期函數包括:(ab)

a: componentWillMount,b:render,c:componentDidUpdate,d:shouldComponentUpdate

在自定義的react組件中,哪些生命周期函數可以不寫(acd)

a: constructor b:render c:componentWillMount d:componentWillUnmount

說法正確的是:(ab)

a: 父組件通過屬性的方式給子組件傳值,b:子組件通過props接收父組件的值,c:state中和頁面無關的屬性發送變化時,render不會執行,d:shouldComponentUpdate函數的兩個參數分別是當前的state和當前的props

在react組件中,當(props或者state)發送變化的時候,會導致render生命周期函數重新執行

使用react-redux時,頁面上的組件需要被拆分成(容器)組件和(UI)組件,通過使用(connect/mapStateToProps)方法,可以把store中固定state內容映射到組件上

使用ES6創建react組件的方式是(class ... extends React.Component),ES5創建組件的方法是(React.createClass),創建無狀態組件的方式是(function(props){return ()})

react中,ref屬性的作用是(獲取jsx中元素的真實dom節點或子組件)

es5語法創建react組件比es6多了兩個生命周期函數(getDefaultProps/getInitialState)

請簡述react-router中hashHistory和browserHistory的區別:

這是react-router中設置監聽url路徑變化的兩種方式,hashHistory在切換路由的時候會在url上跟著哈希值,browserHistory通過判斷path變化才切換路由,且path變化的時候后端可以接收到請求,需要后端配置忽略掉

請畫圖說明flux中的單向數據流

用戶訪問View-》view發出用戶的action-》dispatcher收到action要求store進行更新-》store更改后,觸發一個事件-》view接收到該事件的觸發,更新頁面

簡述react-redux的用法

創建store、reducer,通過provider將store傳遞給各個子組件,創建ui組件,生成容器組件,利用connect將store和容器組件連接

說明redux設計和使用的三大原則:

唯一數據源、保持狀態只讀、數據改變只能通過純函數完成

說明redux-thunk的使用方法:

npm install redux-thunk -S

//store import {createStore,applyMiddleware} from 'redux' import thunk from 'redux-thunk'

import reducer from './reducer'

const store = createStore(reducer,applyMiddleware(thunk))

//actionCreator

const actionCreator = { handlerChange(){ return (dispatch)=>{

? ? ? ? ...

? ? }

}

}

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容