React.js 2016 最佳实践 徬梓阅读 1584收藏 71
為什么80%的碼農(nóng)都做不了架構(gòu)師?>>> ??
譯者按:近幾個(gè)月React相關(guān)話題依舊火熱,相信越來(lái)越多的開(kāi)發(fā)者在嘗試這樣一項(xiàng)技術(shù),我們團(tuán)隊(duì)也在PC和移動(dòng)端不斷總結(jié)經(jīng)驗(yàn)。2016來(lái)了,這應(yīng)該是 React走向成熟的一年,不管你是新手,還是已經(jīng)對(duì)React有所了解,是時(shí)候總結(jié)一下最佳實(shí)踐了,讓我們看看國(guó)外的開(kāi)發(fā)者總結(jié)了哪些好的實(shí)踐吧~
========================譯文分割線===========================
2015可以算是React之年了,關(guān)于其版本發(fā)布和開(kāi)發(fā)者大會(huì)的話題遍布全球。關(guān)于去年React的發(fā)展里程碑詳情,可以查看我們整理的React 2015這一年。
2016年最有趣的問(wèn)題可能是,我們?cè)撊绾尉帉?xiě)一個(gè)應(yīng)用呢,有什么推薦的庫(kù)或框架?
作為一個(gè)長(zhǎng)時(shí)間使用React.js的開(kāi)發(fā)者,我已經(jīng)有自己的答案和最佳實(shí)踐了,但你可能不會(huì)同意我說(shuō)的所有點(diǎn)。我對(duì)你的想法和意見(jiàn)很感興趣,請(qǐng)留言進(jìn)行討論。
如果你只是剛開(kāi)始接觸React.js,請(qǐng)閱讀React.js教程,或Pete Hunt的React ? ? ? ?howto。
數(shù)據(jù)處理
在React.js應(yīng)用中處理數(shù)據(jù)超級(jí)簡(jiǎn)單的,但同時(shí)還是有些挑戰(zhàn)。
這是因?yàn)槟憧梢允褂枚喾N方式,來(lái)給一個(gè)React組件傳遞屬性數(shù)據(jù),從而構(gòu)建出渲染樹(shù)。但這種方式并不總是能明顯地看出,你是否應(yīng)該更新某些視圖。
2015開(kāi)始涌現(xiàn)出一批具有更強(qiáng)功能和響應(yīng)式解決方案的Flux庫(kù),讓我們一起看看:
Flux
根據(jù)我們的經(jīng)驗(yàn),Flux通常被過(guò)度使用了(就是大家在不需使用的場(chǎng)景下,還是使用了)。
Flux提供了一種清爽的方式存儲(chǔ)和管理應(yīng)用的狀態(tài),并在需要的時(shí)候觸發(fā)渲染。
Flux對(duì)于那些應(yīng)用的全局state(譯者注:為了對(duì)應(yīng)React中的state概念,本文將不對(duì)state進(jìn)行翻譯)特別有用,比如:管理登錄用戶的狀態(tài)、路由狀態(tài),或是活躍賬號(hào)狀態(tài)。如果使用臨時(shí)變量或者本地?cái)?shù)據(jù)來(lái)處理這些狀態(tài),會(huì)非常讓人頭疼。
我們不建議使用Flux來(lái)管理路由相關(guān)的數(shù)據(jù),比如/items/:itemId。應(yīng)該只是獲取它并存在組件的state中,這種情況下,它會(huì)在組件銷毀時(shí)一起被銷毀。
如果需要Flux的更多信息,建議閱讀The Evolution of Flux Frameworks。
使用Redux
Redux是一個(gè)JavaScript?app的可預(yù)測(cè)state容器。
如果你覺(jué)得需要Flux或者相似的解決方案,你應(yīng)該了解一下redux,并學(xué)習(xí)Dan Abramov的redux入門(mén)指南,來(lái)強(qiáng)化你的開(kāi)發(fā)技能。
Rudux發(fā)展了Flux的思想,同時(shí)降低了其復(fù)雜度。
扁平化state
API通常會(huì)返回嵌套的資源,這讓Flux或Redux架構(gòu)很難處理。我們推薦使用normalizr這類庫(kù)來(lái)盡可能地扁平化state。
像這樣:
const?data?=?normalize(response,?arrayOf(schema.user))state?=?_.merge(state,?data.entities)? ? ? ?
(我們使用isomorphic-fetch與API進(jìn)行通信)
使用immutable state
共享的可變數(shù)據(jù)是罪惡的根源——Pete Hunt, React.js Conf 2015
不可變對(duì)象是指在創(chuàng)建后不可再被修改的對(duì)象。
不可變對(duì)象可以減少那些讓我們頭痛的工作,并且通過(guò)引用級(jí)的比對(duì)檢查來(lái)提升渲染性能。比如在shouldComponentUpdate中:
shouldComponentUpdate(nexProps)?{??//?不進(jìn)行對(duì)象的深度對(duì)比return?this.props.immutableFoo?!==?nexProps.immutableFoo }? ? ? ?
如何在JavaScript中實(shí)現(xiàn)不可變
比較麻煩的方式是,小心地編寫(xiě)下面的例子,總是需要使用deep-freeze-node(在變動(dòng)前進(jìn)行凍結(jié),結(jié)束后驗(yàn)證結(jié)果)進(jìn)行單元測(cè)試。
return?{??...state,foo }return?arr1.concat(arr2)? ? ? ?
相信我,這是最明顯的例子了。
更簡(jiǎn)單自然的方式,就是使用Immutable.js。
import?{?fromJS?}?from?'immutable'const?state?=?fromJS({?bar:?'biz'?})?? const?newState?=?foo.set('bar',?'baz')? ? ? ?
Immutable.js非常快,其背后的思想也非常美妙。就算沒(méi)準(zhǔn)備使用它,還是推薦你去看看Lee Byron的視頻Immutable ? ? ? ?Data and React,可以了解到它內(nèi)部的實(shí)現(xiàn)原理。
Observables and reactive解決方案
如果你不喜歡Flux/Redux,或者想要更加reactive,不用失望!還有很多方案供你選擇,這里是你可能需要的:
路由
現(xiàn)在幾乎所有app都有路由功能。如果你在瀏覽器中使用React.js,你將會(huì)接觸到這個(gè)點(diǎn),并為其選擇一個(gè)庫(kù)。
我們選擇的是出自優(yōu)秀rackt社區(qū)的react-router,這個(gè)社區(qū)總是能為React.js愛(ài)好者們帶來(lái)高質(zhì)量的資源。
要使用react-router需要查看它的文檔,但更重要的是:如果你使用Flux/Redux,我們推薦你將路由state與store或全局state保持同步。
同步路由state可以讓Flux/Redux來(lái)控制路由行為,并讓組件讀取到路由信息。
Redux的用戶可以使用redux-simple-router來(lái)省點(diǎn)事兒。
代碼分割,懶加載
只有一小部分webpack的用戶知道,應(yīng)用代碼是可以分割成多個(gè)js包的。
require.ensure([],?()?=>?{??const?Profile?=?require('./Profile.js')this.setState({currentComponent:?Profile}) })? ? ? ?
這對(duì)于大型應(yīng)用十分有用,因?yàn)橛脩魹g覽器不用下載那些很少會(huì)使用到的代碼,比如Profile頁(yè)。
多js包會(huì)導(dǎo)致額外的HTTP請(qǐng)求數(shù),但對(duì)于HTTP/2的多路復(fù)用,完全不是問(wèn)題。
與chunk hashing?結(jié)合可以優(yōu)化緩存命中率。
下個(gè)版本的react-router將會(huì)對(duì)代碼分隔做更多支持。
對(duì)于react-router的未來(lái)規(guī)劃,可以去看博文Ryan Florence:?Welcome to Future of Web Application Delivery。
組件
很多人都在抱怨JSX,但首先要知道,它只是React中可選的一項(xiàng)能力。
最后,它們都會(huì)被Bable編譯成JavaScript。你可以繼續(xù)使用JavaScript編寫(xiě)代碼,但是在處理HTML時(shí)使用JSX會(huì)感覺(jué)更自然。特別是對(duì)于那些不懂js的人,他們可以只修改HTML相關(guān)的部分。
JSX是一個(gè)類似于XML的JavaScript擴(kuò)展,可以配合一個(gè)簡(jiǎn)單的語(yǔ)法編譯工具來(lái)使用它。——深入淺出JSX
如果你想了解更多JSX的內(nèi)容,查看文章JSX Looks Like An Abomination – But it’s Good for ? ? ? ?You。
使用類
React中可以順暢地使用ES2015的Class語(yǔ)法。
class?HelloMessage?extends?React.Component?{??render()?{return?<div>Hello?{this.props.name}</div>} }? ? ? ?
我們?cè)诟唠A組件和mixins之間更看重前者,所以拋棄createClass更像是一個(gè)語(yǔ)法問(wèn)題,而不是技術(shù)問(wèn)題。(譯者注:在Class語(yǔ)法 中,React組件的mixins方法將無(wú)法使用。)我們認(rèn)為使用createClass和React.Component沒(méi)有對(duì)錯(cuò)之分。
屬性類型(PropType)
如果你以前不檢查props的類型,那么2016你應(yīng)該開(kāi)始改正了。它會(huì)幫你節(jié)省未來(lái)很多時(shí)間,相信我。
<coed>MyComponent.propTypes?=?{??isLoading:?PropTypes.bool.isRequired,items:?ImmutablePropTypes.listOf(ImmutablePropTypes.contains({name:?PropTypes.string.isRequired,})).isRequired }</coed>? ? ? ?
是的,同時(shí)也盡可能使用react-immutable-proptypes檢查Immutable.js的props。
高階組件(Higher order components)
minins將死,ES6的Class將不對(duì)其進(jìn)行支持,我們需要尋找新的方法。
什么是高階組件?
PassData({?foo:?'bar'?})(MyComponent)? ? ? ?
簡(jiǎn)單地,你創(chuàng)建一個(gè)從原生組件繼承下來(lái)的組件,并且擴(kuò)展了原始組件的行為。你可以在多種場(chǎng)景來(lái)使用它,比如鑒權(quán):requireAuth({ ? ? ? ?role: 'admin' ? ? ? ?})(MyComponent)(檢查用戶是否在高級(jí)組件中,如果還沒(méi)有登錄就進(jìn)行跳轉(zhuǎn)),或者將組件與Flux/Redux的store相連通。
在RisingStack,我們也喜歡分離數(shù)據(jù)拉取和controller類的邏輯到高階組件中,這樣可以盡可能地保持view層的簡(jiǎn)單。
測(cè)試
好的代碼覆蓋測(cè)試是開(kāi)發(fā)周期中的重要一環(huán)。幸運(yùn)的是,React.js社區(qū)有很多這樣的庫(kù)來(lái)幫助我們。
組件測(cè)試
我們最喜愛(ài)的組件測(cè)試庫(kù)是AirBnb的enzyme。有了它的淺渲染特性,可以對(duì)組件的邏輯和渲染結(jié)果進(jìn)行測(cè)試,非常棒對(duì)不對(duì)?它現(xiàn)在還不能替代selenium測(cè)試,但是將前端測(cè)試提升到了一個(gè)新高度。
it('simulates?click?events',?()?=>?{??const?onButtonClick?=?sinon.spy()const?wrapper?=?shallow(<Foo?onButtonClick={onButtonClick}?/>)wrapper.find('button').simulate('click')expect(onButtonClick.calledOnce).to.be.true })? ? ? ?
看起來(lái)很清爽,不是嗎?
你使用chai來(lái)作為斷言庫(kù)嗎?你會(huì)喜歡chai-enyzime的。
Redux測(cè)試
測(cè)試一個(gè)reducer非常簡(jiǎn)單,它響應(yīng)actions然后將原來(lái)的state轉(zhuǎn)為新的state:
it('should?set?token',?()?=>?{??const?nextState?=?reducer(undefined,?{type:?USER_SET_TOKEN,token:?'my-token'})//?immutable.js?state?outputexpect(nextState.toJS()).to.be.eql({token:?'my-token'}) })? ? ? ?
測(cè)試actions也很簡(jiǎn)單,但是異步actions就不一樣了。測(cè)試異步的redux ? ? ? ?actions我們推薦redux-mock-store,它能幫不少忙。
it('should dispatch action', (done) => { ? ?const getState = {} ?const action = { type: 'ADD_TODO' } ?const expectedActions = [action] ?const store = mockStore(getState, expectedActions, done) ?store.dispatch(action) }) ? ? ? ?
關(guān)于更深入的redux測(cè)試,請(qǐng)參考官方文檔。
使用npm
雖然React.js并不依賴代碼構(gòu)建工具,我們推薦Webpack和Browserify,它們都具有npm出色的能力。Npm有很多React.js的package,還可以幫助你優(yōu)雅地管理依賴。
(請(qǐng)不要忘記復(fù)用你自己的組件,這是優(yōu)化代碼的絕佳方式。)
包大小(Bundle size)
這本身不是一個(gè)React相關(guān)的問(wèn)題,但多數(shù)人都會(huì)對(duì)其React進(jìn)行打包,所以我在這里提一下。
當(dāng)你對(duì)源代碼進(jìn)行構(gòu)建時(shí),要保持對(duì)包大小的關(guān)注。要將其控制在最小體積,你需要思考如何require/import依賴。
查看下面的代碼片段,有兩種方式可以對(duì)輸出產(chǎn)生重大影響:
import?{?concat,?sortBy,?map,?sample?}?from?'lodash'//?vs. import?concat?from?'lodash/concat';?? import?sortBy?from?'lodash/sortBy';?? import?map?from?'lodash/map';?? import?sample?from?'lodash/sample';? ? ? ?
查看Reduce Your bundle.js File Size By Doing This One ? ? ? ?Thing,獲取更多詳情。
我們喜歡將代碼分隔到vendors.js和app.js,因?yàn)榈谌酱a的更新頻率比我們自己帶嗎低很多。
對(duì)輸出文件進(jìn)行hash命名(WebPack中的chunk ? ? ? ?hash),并使用長(zhǎng)緩存,我們可以顯著地減少訪問(wèn)用戶需要下載的代碼。結(jié)合代碼懶加載,優(yōu)化效果可想而知。
如果你對(duì)WebPack還很陌生,可以去看超贊的React webpack指南。
組件級(jí)的hot reload
如果你曾使用livereload寫(xiě)過(guò)單頁(yè)面應(yīng)用,你可能知道當(dāng)在處理一些與狀態(tài)相關(guān)的事情,一點(diǎn)代碼保存整個(gè)頁(yè)面就刷新了,這種體驗(yàn)有多煩人。你需要逐步點(diǎn)擊操作到剛才的環(huán)節(jié),然后在這樣的重復(fù)中奔潰。
在React開(kāi)發(fā)中,是可以reload一個(gè)組件,同時(shí)保持它的state不變——耶,從此無(wú)需苦惱!
搭建hot reload,可參考react-transform-boilerplate。
使用ES2015
前面提到過(guò),在React.js中使用的JSX,最終會(huì)被Babel.js進(jìn)行編譯。
Bable的能力還不止這些,它可以讓我們?cè)跒g覽器中放心地使用ES6/ES2015。在RisingStack,我們?cè)诜?wù)器端和客戶端都使用了ES2015的特性,ES2015已經(jīng)可以在最新的LTS ? ? ? ?Node.js版本中使用了。
代碼檢查(Linters)
也許你已經(jīng)對(duì)你的代碼制定了代碼規(guī)范,但是你知道React的各種代碼規(guī)范嗎?我們建議你選擇一個(gè)代碼規(guī)范,然后照著下面說(shuō)的來(lái)做。
在RisingStack,我們強(qiáng)制將linters運(yùn)行在持續(xù)集成(CI)系統(tǒng),已經(jīng)git push功能上。查看pre-push和pre-commit。
我們使用標(biāo)準(zhǔn)的JavaScript代碼風(fēng)格,并使用eslint-plugin-react來(lái)檢查React.js代碼。
(是的,我們已經(jīng)不再使用分號(hào)了)
GraphQL和Relay
GraphQL和Relay是相關(guān)的新技術(shù)。在RisingStack,我們不在生產(chǎn)環(huán)境使用它們,暫時(shí)保持關(guān)注。
我們寫(xiě)了一個(gè)Relay的MongoDB ORM,叫做graffiti,可以使用你已有的mongoose models來(lái)創(chuàng)建GraphQL server。
如果你想學(xué)習(xí)這些新技術(shù),我們建議你去看看這個(gè)庫(kù),然后寫(xiě)幾個(gè)demo玩玩。
這些React.js最佳實(shí)踐的核心點(diǎn)
有些優(yōu)秀的技術(shù)和庫(kù)其實(shí)跟React都沒(méi)什么關(guān)系,關(guān)鍵在于要關(guān)注社區(qū)都在做些什么。2015這一年,React社區(qū)被Elm架構(gòu)啟發(fā)了很多。
如果你知道其他2016年大家應(yīng)該使用的React.js工具,請(qǐng)留言告訴我們。
轉(zhuǎn)載于:https://my.oschina.net/Gxhpro/blog/610131
與50位技術(shù)專家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的React.js 2016 最佳实践 徬梓阅读 1584收藏 71的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: iOS之路9-#import 与#inc
- 下一篇: nginx tomcat负载均衡配置