react技術棧全家桶(總結及感悟)

baldwin發表於2018-04-20

簡介

react確實是一個神奇而優雅的框架。在從事react專案之前,一直是在做angular的,angular是一個全面和龐大的框架,在起初設計的時候什麼都有,複雜程度也很高,所以用angular做專案基本上不需要其他的輔助庫來配合。但是react專案真的是不一樣了,要是隻會一個react的話,很難開發出需求的。因為react就只負責UI的渲染。

這裡是我開發react工程的一個模板,平時開發過程中遇到的需求上面都有對應的例項,技術棧:react + react-router + react-redux + saga + reselector + webpack + ES6 + Typescript + sass點選這裡訪問

做react專案需要掌握什麼

react技術棧全家桶(總結及感悟)
react 功能單一用於UI渲染,redux 用來管理資料,react-router 用來管理路由,webpack 用來配置工程,ES6 讓程式碼更加優雅,redux-saga 用來處理非同步請求,reselect 快取機制用來減少state改變帶來的渲染壓力,還有一些為了互動衍生出來的中介軟體 react-reduxreact-router-reduxreact-router-dom ,前處理器SassLess 儘量也掌握下。

react

前面有說過react只負責ui的渲染

從V-dom出發

react最難能可貴的就是虛擬dom的思想,這裡有個貼切的比喻:把dom和JavaScript想象為各自的2個島嶼,中間有橋樑相連,但是橋上設有收費站,JavaScript去訪問dom島嶼的次數越多,費用就越高。這就是一個js操作dom的過程,也許我們經常聽到或者看到說盡量少的去操作dom,很耗效能。但是DOM 操作成本到底高在哪兒?,這邊小總結下:

從輸入uri到頁面載入好是一個很漫長的過程,我們就從html的解析開始說起。①解析HTML,開始構建DOM樹;②解析CSS,生成CSS規則樹;③合併DOM樹和CSS規則樹,生成render樹;④佈局render樹(Layout/reflow),這時候負責元素尺寸大小,位置的計算,屬於js中迴流過程;⑤繪製render樹(paint),繪製頁面畫素,屬於重繪的過程;⑥瀏覽器會將各層的資訊傳送給GPU(影像處理器),GPU將各層合成(composite),顯示在螢幕上。這是初始化渲染的過程,通過js操作DOM後,會引起 迴流 和重繪,迴流的成本很高,一個節點的迴流會導致兄弟節點和子節點的迴流,這樣就一直在消耗GPU資源,所以才有了成本高的說法。

我們從操作dom的成本開始引入react,它創造了虛擬dom並且將它們儲存起來,每當狀態發生變化的時候就會創造新的虛擬節點和以前的進行對比,讓變化的部分進行渲染。整個過程沒有對dom進行獲取和操作,只有等真正render時,才會去操作真實dom,從而引發頁面的渲染。

V-dom的缺點

ReactJS 使用虛擬 DOM 機制,讓前端開發者為每個元件提供一個 render 函式。render 函式把 props 和 state 轉換成 ReactJS 的虛擬 DOM,然後 ReactJS 框架根據render 返回的虛擬 DOM 建立相同結構的真實 DOM。

每當 state 更改時,ReactJS 框架重新呼叫 render 函式,獲取新的虛擬 DOM 。然後,框架會比較上次生成的虛擬 DOM 和新的虛擬 DOM 有哪些差異,進而把差異應用到真實 DOM 上。

這樣做有兩大缺點:

//每次 state 更改,render 函式都要生成完整的虛擬 DOM,哪怕 state 改動很小,
//render函式也會完整計算一遍。如果 render 函式很複雜,這個過程就會白白浪費很多計算資源。

//ReactJS 框架比較虛擬 DOM 差異的過程,既慢又容易出錯。比如,你想要在某個 <ul> 列表的頂部插入一項 <li> ,
//那麼 ReactJS 框架會誤以為你修改了 <ul> 的每一項 <li>,然後在尾部插入了一個 <li>。
複製程式碼

這是因為 ReactJS 收到的新舊兩個虛擬 DOM 之間相互獨立,ReactJS 並不知道資料來源發生了什麼操作,只能根據新舊兩個虛擬 DOM 來猜測需要執行的操作。自動的猜測演算法既不準又慢,必須要前端開發者手動提供 key 屬性、shouldComponentUpdate 方法、componentDidUpdate 方法或者 componentWillUpdate 等方法才能幫助 ReactJS 框架猜對。

diff演算法

react的diff演算法用在什麼地方呢?當元件更新的時候,react會建立一個新的虛擬dom樹並且會和之前儲存的dom樹進行比較,這個比較的過程就用到了diff演算法,所以元件初始化的時候是用不到的。react提出了一種假設,相同的節點具有類似的結構,而不同的節點具有不同的結構。在這種假設之上進行逐層的比較,如果發現對應的節點是不同的,那就直接刪除舊的節點以及它所包含的所有子節點然後替換成新的節點。如果是相同的節點,則只進行屬性的更改。

對於列表的diff演算法稍有不同,因為列表通常具有相同的結構,在對列表節點進行刪除,插入,排序的時候,單個節點的整體操作遠比一個個對比一個個替換要好得多,所以在建立列表的時候需要設定key值,這樣react才能分清誰是誰。當然不寫key值也可以,但這樣通常會報出警告,通知我們加上key值以提高react的效能。

react技術棧全家桶(總結及感悟)

需要深入瞭解diff原始碼的請參考原始碼解析

單項資料流

react技術棧全家桶(總結及感悟)

元件化

元件就是擁有獨立功能的檢視模組,React的最大好處在於:功能元件化,遵守前端可維護的原則。

元件生命週期

react技術棧全家桶(總結及感悟)

元件初始化會觸發的5個鉤子函式

1.getDefaultProps()

設定預設的props,也可以用defaultProps設定元件的預設屬性。

getDefaultProps相當於ES6中的 static defaultProps = {}

2.getInitialState()

在使用es6的class語法時是沒有這個鉤子函式的,可以直接在constructor中定義this.state。此時可以訪問this.props。

getInitialState相當於ES6 class中constructor的 this.state = {}

鉤子函式1 2 只有用React.createClass方法創造的元件類才會發生作用,並且React.createClass已經被Fb官方廢棄,所以這裡不細講了。

3.componentWillMount()

元件初始化時只呼叫,以後元件更新不呼叫,整個生命週期只呼叫一次,此時可以修改state。

4.render()

react最重要的步驟,建立虛擬dom,進行diff演算法,更新dom樹都在此進行。

render() 應該是一個純函式,完全根據state和props來決定返回結果,而不產生副作用,所以render中呼叫setState是錯的,因為純函式不應該引起狀態的改變

5.componentDidMount()

元件渲染之後呼叫,可以通過this.getDOMNode()獲取和操作dom節點,只呼叫一次。

did的字首表示進入狀態之後呼叫,比如componentDidMount,元件一般初始化都會在這裡進行資料請求。

為什麼請求資料要在這個鉤子函式裡面呼叫?

我的總結詳見react中遇到的一些問題的解答

元件互動更新時觸發的5個鉤子函式

6.componentWillReceiveProps(nextProps)

元件初始化時不呼叫,元件接受新的props時呼叫。

開發過程中一般是在這個鉤子函式裡面改變state,此方法中改變state不會二次渲染而是進行state合併。

7.shouldComponentUpdate(nextProps, nextState)

react效能優化非常重要的一環。元件接受新的state或者props時呼叫,我們可以設定在此對比前後兩個props和state是否相同,如果相同則返回false阻止更新,因為相同的屬性狀態一定會生成相同的dom樹,這樣就不需要創造新的dom樹和舊的dom樹進行diff演算法對比,節省大量效能,尤其是在dom結構複雜的時候。不過呼叫this.forceUpdate會跳過此步驟。

8.componentWillUpdate(nextProps, nextState)

元件初始化時不呼叫,只有在元件將要更新時才呼叫。

千萬不要在這個函式中呼叫this.setState()方法,會造成迴圈呼叫。

9.render()

同上render(),建立虛擬dom,進行diff演算法,更新dom樹都在此進行。

10.componentDidUpdate()

元件初始化時不呼叫,元件更新完成後呼叫,此時可以獲取dom節點。

在componentDidUpdate後才能獲取更新後的this.state。如果想獲取元件預設的props,並且賦值給State ,就可以在這裡修改,達到UI上的效果。

元件解除安裝時呼叫

10.componentWillUnmount()

元件將要解除安裝時呼叫,一些事件監聽和定時器需要在此時清除,還有此元件store上面的值也可以對應的清楚。

componentWillUnmount執行重置所有相關引數。在該方法中呼叫setState不會觸發render,因為所有的更新佇列,更新狀態都被重置為null。

//資料清楚需要寫在reducer裡面
this.props.clearPointData();

[CLEAR_POINT_DATA]: (state, action: Action<any>) => {
    return Object.assign({}, state, {
        selectedReadingList: {},
        knowledgePoint: {},
    });
}
複製程式碼

以上可以看出來react總共有10個周期函式(render重複一次),這個10個函式可以滿足我們所有對元件操作的需求,利用的好可以提高開發效率和元件效能。

react-router

react技術棧全家桶(總結及感悟)
Router就是React的一個元件,它並不會被渲染,只是一個建立內部路由規則的配置物件,根據匹配的路由地址展現相應的元件。Route則對路由地址和元件進行繫結,Route具有巢狀功能,表示路由地址的包涵關係,這和元件之間的巢狀並沒有直接聯絡。Route可以向繫結的元件傳遞7個屬性:children,history,location,params,route,routeParams,routes,每個屬性都包涵路由的相關的資訊。比較常用的有children(以路由的包涵關係為區分的元件),location(包括地址,引數,地址切換方式,key值,hash值)。react-router提供Link標籤,這只是對a標籤的封裝,值得注意的是,點選連結進行的跳轉並不是預設的方式,react-router阻止了a標籤的預設行為並用pushState進行hash值的轉變。切換頁面的過程是在點選Link標籤或者後退前進按鈕時,會先發生url地址的轉變,Router監聽到地址的改變根據Route的path屬性匹配到對應的元件,將state值改成對應的元件並呼叫setState觸發render函式重新渲染dom。

當頁面比較多時,專案就會變得越來越大,尤其對於單頁面應用來說,初次渲染的速度就會很慢,這時候就需要按需載入,只有切換到頁面的時候才去載入對應的js檔案。react配合webpack進行按需載入的方法很簡單,Route的component改為getComponent,元件用require.ensure的方式獲取,並在webpack中配置chunkFilename。

const chooseProducts = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('../Component/chooseProducts').default)
    },'chooseProducts')
}

const helpCenter = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('../Component/helpCenter').default)
    },'helpCenter')
}

const saleRecord = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('../Component/saleRecord').default)
    },'saleRecord')
}

const RouteConfig = (
    <Router history={history}>
        <Route path="/" component={Roots}>
            <IndexRoute component={index} />//首頁
            <Route path="index" component={index} />
            <Route path="helpCenter" getComponent={helpCenter} />//幫助中心
            <Route path="saleRecord" getComponent={saleRecord} />//銷售記錄
            <Redirect from='*' to='/'  />
        </Route>
    </Router>
);
複製程式碼

react-router-redux

保持路由與應用狀態(state)同步。使用redux管理應用狀態(state),使用router管理路由,兩個庫不能協同工作,react-router-redux庫可以協調這兩個庫。

react-router-dom

...

redux

react技術棧全家桶(總結及感悟)

元件間的通訊

react推崇的是單向資料流,自上而下進行資料的傳遞,但是由下而上或者不在一條資料流上的元件之間的通訊就會變的複雜。解決通訊問題的方法很多,如果只是父子級關係,父級可以將一個回撥函式當作屬性傳遞給子級,子級可以直接呼叫函式從而和父級通訊。

元件層級巢狀到比較深,可以使用上下文getChildContext來傳遞資訊,這樣在不需要將函式一層層往下傳,任何一層的子級都可以通過this.context直接訪問。

兄弟關係的元件之間無法直接通訊,它們只能利用同一層的上級作為中轉站。而如果兄弟元件都是最高層的元件,為了能夠讓它們進行通訊,必須在它們外層再套一層元件,這個外層的元件起著儲存資料,傳遞資訊的作用,這其實就是redux所做的事情。

元件之間的資訊還可以通過全域性事件來傳遞。不同頁面可以通過引數傳遞資料,下個頁面可以用location.param來獲取。其實react本身很簡單,難的在於如何優雅高效的實現元件之間資料的交流。

redux

首先,redux並不是必須的,它的作用相當於在頂層元件之上又加了一個元件,作用是進行邏輯運算、儲存資料和實現元件尤其是頂層元件的通訊。如果元件之間的交流不多,邏輯不復雜,只是單純的進行檢視的渲染,這時候用回撥,context就行,沒必要用redux,用了反而影響開發速度。但是如果元件交流特別頻繁,邏輯很複雜,那redux的優勢就特別明顯了。我第一次做react專案的時候並沒有用redux,所有的邏輯都是在元件內部實現,當時為了實現一個邏輯比較複雜的購物車,洋洋灑灑居然寫了800多行程式碼,回頭一看我自己都不知道寫的是啥,畫面太感人。

先簡單說一下redux和react是怎麼配合的。react-redux提供了connect和Provider兩個好基友,它們一個將元件與redux關聯起來,一個將store傳給元件。元件通過dispatch發出action,store根據action的type屬性呼叫對應的reducer並傳入state和這個action,reducer對state進行處理並返回一個新的state放入store,connect監聽到store發生變化,呼叫setState更新元件,此時元件的props也就跟著變化。

流程是這個樣子的:

react技術棧全家桶(總結及感悟)

值得注意的是connect,Provider,mapStateToProps,mapDispatchToProps是react-redux提供的,redux本身和react沒有半毛錢關係,它只是資料處理中心,沒有和react產生任何耦合,是react-redux讓它們聯絡在一起。

接下來具體分析一下,redux以及react-redux到底是怎麼實現的。

先上一張圖

react技術棧全家桶(總結及感悟)

明顯比第一張要複雜,其實兩張圖說的是同一件事。從上而下慢慢分析:

先說說redux

redux主要由三部分組成:store,reducer,action。

store是一個物件,它有四個主要的方法:

1、dispatch:

用於action的分發----在createStore中可以用middleware中介軟體對dispatch進行改造,比如當action傳入dispatch會立即觸發reducer,有些時候我們不希望它立即觸發,而是等待非同步操作完成之後再觸發,這時候用redux-thunk對dispatch進行改造,以前只能傳入一個物件,改造完成後可以傳入一個函式,在這個函式裡我們手動dispatch一個action物件,這個過程是可控的,就實現了非同步。

2、subscribe:

監聽state的變化----這個函式在store呼叫dispatch時會註冊一個listener監聽state變化,當我們需要知道state是否變化時可以呼叫,它返回一個函式,呼叫這個返回的函式可以登出監聽。 let unsubscribe = store.subscribe(() => {console.log('state發生了變化')})

3、getState:

獲取store中的state----當我們用action觸發reducer改變了state時,需要再拿到新的state裡的資料,畢竟資料才是我們想要的。getState主要在兩個地方需要用到,一是在dispatch拿到action後store需要用它來獲取state裡的資料,並把這個資料傳給reducer,這個過程是自動執行的,二是在我們利用subscribe監聽到state發生變化後呼叫它來獲取新的state資料,如果做到這一步,說明我們已經成功了。

4、replaceReducer:

替換reducer,改變state修改的邏輯。

action:

action是一個物件,其中type屬性是必須的,同時可以傳入一些資料。action可以用actionCreactor進行創造。dispatch就是把action物件傳送出去。

reducer:

reducer是一個函式,它接受一個state和一個action,根據action的type返回一個新的state。根據業務邏輯可以分為很多個reducer,然後通過combineReducers將它們合併,state樹中有很多物件,每個state物件對應一個reducer,state物件的名字可以在合併時定義。

像這個樣子:

const reducer = combineReducers({
     a: doSomethingWithA,
     b: processB,
     c: c
})
複製程式碼

combineReducers:

其實它也是一個reducer,它接受整個state和一個action,然後將整個state拆分傳送給對應的reducer進行處理,所有的reducer會收到相同的action,不過它們會根據action的type進行判斷,有這個type就進行處理然後返回新的state,沒有就返回預設值,然後這些分散的state又會整合在一起返回一個新的state樹。

接下來分析一下整體的流程,首先呼叫store.dispatch將action作為引數傳入,同時用getState獲取當前的狀態樹state並註冊subscribe的listener監聽state變化,再呼叫combineReducers並將獲取的state和action傳入。combineReducers會將傳入的state和action傳給所有reducer,並根據action的type返回新的state,觸發state樹的更新,我們呼叫subscribe監聽到state發生變化後用getState獲取新的state資料。

redux的state和react的state兩者完全沒有關係,除了名字一樣。

上面分析了redux的主要功能,那麼react-redux到底做了什麼?

react-redux

如果只使用redux,那麼流程是這樣的:

component --> dispatch(action) --> reducer --> subscribe --> getState --> component

用了react-redux之後流程是這樣的:

component --> actionCreator(data) --> reducer --> component

store的三大功能:dispatch,subscribe,getState都不需要手動來寫了。react-redux幫我們做了這些,同時它提供了兩個好基友Provider和connect。

Provider是一個元件,它接受store作為props,然後通過context往下傳,這樣react中任何元件都可以通過context獲取store。也就意味著我們可以在任何一個元件裡利用dispatch(action)來觸發reducer改變state,並用subscribe監聽state的變化,然後用getState獲取變化後的值。但是並不推薦這樣做,它會讓資料流變的混亂,過度的耦合也會影響元件的複用,維護起來也更麻煩。

connect --connect(mapStateToProps, mapDispatchToProps, mergeProps, options) 是一個函式,它接受四個引數並且再返回一個函式--wrapWithConnect,wrapWithConnect接受一個元件作為引數wrapWithConnect(component),它內部定義一個新元件Connect(容器元件)並將傳入的元件(ui元件)作為Connect的子元件然後return出去。

所以它的完整寫法是這樣的:connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(component)

mapStateToProps(state, [ownProps]):

mapStateToProps 接受兩個引數,store的state和自定義的props,並返回一個新的物件,這個物件會作為props的一部分傳入ui元件。我們可以根據元件所需要的資料自定義返回一個物件。ownProps的變化也會觸發mapStateToProps

function mapStateToProps(state) {
   return { todos: state.todos };
}
複製程式碼

mapDispatchToProps(dispatch, [ownProps]):

mapDispatchToProps如果是物件,那麼會和store繫結作為props的一部分傳入ui元件。如果是個函式,它接受兩個引數,bindActionCreators會將action和dispatch繫結並返回一個物件,這個物件會和ownProps一起作為props的一部分傳入ui元件。所以不論mapDispatchToProps是物件還是函式,它最終都會返回一個物件,如果是函式,這個物件的key值是可以自定義的

function mapDispatchToProps(dispatch) {
   return {
      todoActions: bindActionCreators(todoActionCreators, dispatch),
      counterActions: bindActionCreators(counterActionCreators, dispatch)
   };
}
複製程式碼

mapDispatchToProps返回的物件其屬性其實就是一個個actionCreator,因為已經和dispatch繫結,所以當呼叫actionCreator時會立即傳送action,而不用手動dispatch。ownProps的變化也會觸發mapDispatchToProps。

mergeProps(stateProps, dispatchProps, ownProps):

將mapStateToProps() 與 mapDispatchToProps()返回的物件和元件自身的props合併成新的props並傳入元件。預設返回 Object.assign({}, ownProps, stateProps, dispatchProps) 的結果。

options:

pure = true 表示Connect容器元件將在shouldComponentUpdate中對store的state和ownProps進行淺對比,判斷是否發生變化,優化效能。為false則不對比。

其實connect函式並沒有做什麼,大部分的邏輯都是在它返回的wrapWithConnect函式內實現的,確切的說是在wrapWithConnect內定義的Connect元件裡實現的。

下面是一個完整的 react --> redux --> react 流程:

一、Provider元件接受redux的store作為props,然後通過context往下傳。

二、connect函式在初始化的時候會將mapDispatchToProps物件繫結到store,如果mapDispatchToProps是函式則在Connect元件獲得store後,根據傳入的store.dispatch和action通過bindActionCreators進行繫結,再將返回的物件繫結到store,connect函式會返回一個wrapWithConnect函式,同時wrapWithConnect會被呼叫且傳入一個ui元件,wrapWithConnect內部使用class Connect extends Component定義了一個Connect元件,傳入的ui元件就是Connect的子元件,然後Connect元件會通過context獲得store,並通過store.getState獲得完整的state物件,將state傳入mapStateToProps返回stateProps物件、mapDispatchToProps物件或mapDispatchToProps函式會返回一個dispatchProps物件,stateProps、dispatchProps以及Connect元件的props三者通過Object.assign(),或者mergeProps合併為props傳入ui元件。然後在ComponentDidMount中呼叫store.subscribe,註冊了一個回撥函式handleChange監聽state的變化。

三、此時ui元件就可以在props中找到actionCreator,當我們呼叫actionCreator時會自動呼叫dispatch,在dispatch中會呼叫getState獲取整個state,同時註冊一個listener監聽state的變化,store將獲得的state和action傳給combineReducers,combineReducers會將state依據state的key值分別傳給子reducer,並將action傳給全部子reducer,reducer會被依次執行進行action.type的判斷,如果有則返回一個新的state,如果沒有則返回預設。combineReducers再次將子reducer返回的單個state進行合併成一個新的完整的state。此時state發生了變化。dispatch在state返回新的值之後會呼叫所有註冊的listener函式其中包括handleChange函式,handleChange函式內部首先呼叫getState獲取新的state值並對新舊兩個state進行淺對比,如果相同直接return,如果不同則呼叫mapStateToProps獲取stateProps並將新舊兩個stateProps進行淺對比,如果相同,直接return結束,不進行後續操作。如果不相同則呼叫this.setState()觸發Connect元件的更新,傳入ui元件,觸發ui元件的更新,此時ui元件獲得新的props,react --> redux --> react 的一次流程結束。

react技術棧全家桶(總結及感悟)
上面的有點複雜,簡化版的流程是:

一、Provider元件接受redux的store作為props,然後通過context往下傳。

二、connect函式收到Provider傳出的store,然後接受三個引數mapStateToProps,mapDispatchToProps和元件,並將state和actionCreator以props傳入元件,這時元件就可以呼叫actionCreator函式來觸發reducer函式返回新的state,connect監聽到state變化呼叫setState更新元件並將新的state傳入元件。

connect可以寫的非常簡潔,mapStateToProps,mapDispatchToProps只不過是傳入的回撥函式,connect函式在必要的時候會呼叫它們,名字不是固定的,甚至可以不寫名字。

簡化版本:

connect(state => state, action)(Component);
複製程式碼

redux-saga

有待更新。。。

reselect

react技術棧全家桶(總結及感悟)
在React中最昂貴的操作就是渲染迴路.當元件檢測到輸入的變化,渲染迴路就會被觸發(譯註:這裡的意思的元件的action會改變redux的state,變回最終又回到元件了).

當我們初次開始React程式的時候,我們不會擔心渲染迴路的花銷問題.但是當我們的UI變得複雜的時候,我們需要考慮這一點.React提供了一些工具讓我們能劫持渲染迴路,如果渲染看上去不必要,我們就可以使用工具來阻止重渲染的發生.為了這麼做,我們要敲入componentShouldUpdate生命週期事件,返回一個布林值,通知元件是否應該進行更新.這是以PureRenderMixin作為基礎,它比較輸入的props和state和先前的props和state,如果兩者相等就返回false.

不幸的是,僅此而已.

Reselect用來記憶selectors的庫.我們定義的selectors是作為函式獲取Redux state的某一部分.使用記憶能力,我們可以組織不必要的衍生資料的重渲染和計算過程,由此加速了我們的app.

Reselect這個中介軟體要解決的問題是:在元件互動操作的時候,state發生變化的時候如何減少渲染的壓力.在Reselect中間中使用了快取機制

"selector"是一個簡單的Redux庫

  • Selector可以計算衍生的資料,可以讓Redux做到儲存儘可能少的state。
  • Selector比較高效,只有在某個引數發生變化的時候才發生計算過程.
  • Selector是可以組合的,他們可以作為輸入,傳遞到其他的selector.

參考

-使用Reselect改進React和Redux程式效能

ES6

react技術棧全家桶(總結及感悟)
在react工程當中,ES6/7/8到處可見,所以ES6也必須要掌握,因為內容太多就簡單總結下常用的一些技巧。具體的可參考阮一峰老師的ES6入門

其實ES6相對於ES5來說,新增了很多的東西,列舉些常用的:使用let const完全拋棄var;模板的匯入匯出(import,export);字串的擴充套件(``,${});物件的擴充套件(結構賦值,新增了一些api如assgin(),keys(),is()等;陣列的擴充套件(結構賦值,from(),of(),findIndex(),find()等);函式的擴充套件(函式引數可以設定預設值,箭頭函式,沒有arguments物件等);常用來遍歷的(for of,forEach,for in,map等);用於解決非同步的(generator函式,promise,async/await函式等);class和extends關鍵字等

雖然很多ES6的技巧用ES5同樣能實現,但是ES6大大提高了開發效率,程式碼也更加優雅,況且各類的打包工具都可以將ES6轉化成適配低瀏覽器的ES5,所以推薦大家使用。

webpack

react技術棧全家桶(總結及感悟)

參考webpack官網

Sass or Less

react技術棧全家桶(總結及感悟)

隨著前端的不斷髮展,網站的頁面複雜度也在不斷提升,原生 CSS 已經讓開發者力不從心,前處理器賦予我們的 "超能力"。淺談 CSS 前處理器:為什麼要使用前處理器?

Sass

參考Sass語法

Less

參考Less語法

===================================end==================================

React Prepare

最後附上react技術棧的相關連結,希望對大家有幫助!

react

React 入門例項教程

React 技術棧系列教程

react 元件

React建立元件的三種方式及其區別

從效能角度看react元件拆分的重要性

react 效能篇

React效能優化總結

現代 Web 開發--React 篇

React.js 初學者應該知道的9件事

react router

React Router 使用教程

redux

Redux 入門教程(一):基本用法

Redux 入門教程(二):中介軟體與非同步操作

Redux 入門教程(三):React-Redux 的用法

Redux 中文文件

Redux 英文文件

Redux 核心概念

React 實踐心得:react-redux 之 connect 方法詳解

redux-saga/redux-thunk

saga 中文文件

聊一聊 redux 非同步流之 redux-saga

Redux-Saga 實用指北

Reselect

Others

Flux 架構入門教程

Immutable

dom diff

Generator 函式的含義與用法

react技術棧全家桶(總結及感悟)

相關文章