React.js 2016 最佳實(shí)踐

英文原文:React.js Best Practices for 2016
作者:Péter Márton
轉(zhuǎn)載自AlloyTeam:
http://www.alloyteam.com/2016/01/reactjs-best-practices-for-2016/

譯者按:近幾個月React相關(guān)話題依舊火熱,相信越來越多的開發(fā)者在嘗試這樣一項(xiàng)技術(shù)盏袄,我們團(tuán)隊(duì)也在PC和移動端不斷總結(jié)經(jīng)驗(yàn)芬探。2016來了,這應(yīng)該是React走向成熟的一年璃搜,不管你是新手褐澎,還是已經(jīng)對React有所了解亲善,是時候總結(jié)一下最佳實(shí)踐了凉袱,讓我們看看國外的開發(fā)者總結(jié)了哪些好的實(shí)踐吧~

2015可以算是React之年了傲宜,關(guān)于其版本發(fā)布和開發(fā)者大會的話題遍布全球运杭。關(guān)于去年React的發(fā)展里程碑詳情,可以查看我們整理的React 2015這一年函卒。

2016年最有趣的問題可能是辆憔,我們該如何編寫一個應(yīng)用呢,有什么推薦的庫或框架?

作為一個長時間使用React.js的開發(fā)者躁愿,我已經(jīng)有自己的答案和最佳實(shí)踐了叛本,但你可能不會同意我說的所有點(diǎn)。我對你的想法和意見很感興趣彤钟,請留言進(jìn)行討論来候。

React.js logo - Best Practices for 2016
React.js logo - Best Practices for 2016

如果你只是剛開始接觸React.js,請閱讀React.js教程逸雹,或Pete Hunt的React howto营搅。

數(shù)據(jù)處理

在React.js應(yīng)用中處理數(shù)據(jù)超級簡單的,但同時還是有些挑戰(zhàn)梆砸。

這是因?yàn)槟憧梢允褂枚喾N方式转质,來給一個React組件傳遞屬性數(shù)據(jù),從而構(gòu)建出渲染樹帖世。但這種方式并不總是能明顯地看出休蟹,你是否應(yīng)該更新某些視圖。

2015開始涌現(xiàn)出一批具有更強(qiáng)功能和響應(yīng)式解決方案的Flux庫日矫,讓我們一起看看:

Flux

根據(jù)我們的經(jīng)驗(yàn)赂弓,F(xiàn)lux通常被過度使用了(就是大家在不需使用的場景下,還是使用了)哪轿。

Flux提供了一種清爽的方式存儲和管理應(yīng)用的狀態(tài)盈魁,并在需要的時候觸發(fā)渲染。

Flux對于那些應(yīng)用的全局state(譯者注:為了對應(yīng)React中的state概念窃诉,本文將不對state進(jìn)行翻譯)特別有用杨耙,比如:管理登錄用戶的狀態(tài)、路由狀態(tài)飘痛,或是活躍賬號狀態(tài)珊膜。如果使用臨時變量或者本地?cái)?shù)據(jù)來處理這些狀態(tài),會非常讓人頭疼敦冬。

我們不建議使用Flux來管理路由相關(guān)的數(shù)據(jù)辅搬,比如/items/:itemId。應(yīng)該只是獲取它并存在組件的state中脖旱,這種情況下堪遂,它會在組件銷毀時一起被銷毀。

如果需要Flux的更多信息萌庆,建議閱讀The Evolution of Flux Frameworks溶褪。

使用Redux

Redux是一個JavaScript app的可預(yù)測state容器。

如果你覺得需要Flux或者相似的解決方案践险,你應(yīng)該了解一下redux猿妈,并學(xué)習(xí)Dan Abramovredux入門指南培愁,來強(qiáng)化你的開發(fā)技能们衙。

Rudux發(fā)展了Flux的思想惧互,同時降低了其復(fù)雜度鱼的。

扁平化state

API通常會返回嵌套的資源,這讓Flux或Redux架構(gòu)很難處理俯抖。我們推薦使用normalizr這類庫來盡可能地扁平化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

Immutable logo for React.js Best Practices 2016
Immutable logo for React.js Best Practices 2016

不可變對象是指在創(chuàng)建后不可再被修改的對象。

不可變對象可以減少那些讓我們頭痛的工作芬萍,并且通過引用級的比對檢查來提升渲染性能尤揣。比如在shouldComponentUpdate中:

shouldComponentUpdate(nexProps) {  
 // 不進(jìn)行對象的深度對比
 return this.props.immutableFoo !== nexProps.immutableFoo
}

如何在JavaScript中實(shí)現(xiàn)不可變

比較麻煩的方式是,小心地編寫下面的例子柬祠,總是需要使用deep-freeze-node(在變動前進(jìn)行凍結(jié)北戏,結(jié)束后驗(yàn)證結(jié)果)進(jìn)行單元測試。

return {  
  ...state,
  foo
}
 
return arr1.concat(arr2)

相信我漫蛔,這是最明顯的例子了嗜愈。

更簡單自然的方式,就是使用Immutable.js惩猫。

import { fromJS } from 'immutable'
 
const state = fromJS({ bar: 'biz' })  
const newState = foo.set('bar', 'baz')  

Immutable.js非持ビ玻快蚜点,其背后的思想也非常美妙轧房。就算沒準(zhǔn)備使用它,還是推薦你去看看Lee Byron的視頻Immutable Data and React绍绘,可以了解到它內(nèi)部的實(shí)現(xiàn)原理奶镶。

Observables and reactive解決方案

如果你不喜歡Flux/Redux,或者想要更加reactive陪拘,不用失望厂镇!還有很多方案供你選擇,這里是你可能需要的:

  • cycle.js(“一個更清爽的reactive框架”)
  • rx-flux(“Flux與Rxjs結(jié)合的產(chǎn)物”)
  • redux-rx(“Redux的Rxjs工具庫”)
  • mobservable(“可觀測的數(shù)據(jù)左刽,reactive的功能捺信,簡潔的代碼”)

路由

現(xiàn)在幾乎所有app都有路由功能。如果你在瀏覽器中使用React.js欠痴,你將會接觸到這個點(diǎn)迄靠,并為其選擇一個庫。

我們選擇的是出自優(yōu)秀rackt社區(qū)的react-router喇辽,這個社區(qū)總是能為React.js愛好者們帶來高質(zhì)量的資源掌挚。

要使用react-router需要查看它的文檔,但更重要的是:如果你使用Flux/Redux菩咨,我們推薦你將路由state與store或全局state保持同步吠式。

同步路由state可以讓Flux/Redux來控制路由行為陡厘,并讓組件讀取到路由信息。

Redux的用戶可以使用redux-simple-router來省點(diǎn)事兒特占。

代碼分割糙置,懶加載

只有一小部分webpack的用戶知道,應(yīng)用代碼是可以分割成多個js包的是目。

require.ensure([], () => {  
  const Profile = require('./Profile.js')
  this.setState({
    currentComponent: Profile
  })
})

這對于大型應(yīng)用十分有用罢低,因?yàn)橛脩魹g覽器不用下載那些很少會使用到的代碼,比如Profile頁胖笛。

多js包會導(dǎo)致額外的HTTP請求數(shù)网持,但對于HTTP/2的多路復(fù)用,完全不是問題长踊。

chunk hashing 結(jié)合可以優(yōu)化緩存命中率功舀。

下個版本的react-router將會對代碼分隔做更多支持。

對于react-router的未來規(guī)劃身弊,可以去看博文Ryan Florence: Welcome to Future of Web Application Delivery辟汰。

組件

很多人都在抱怨JSX,但首先要知道阱佛,它只是React中可選的一項(xiàng)能力帖汞。

最后,它們都會被Bable編譯成JavaScript凑术。你可以繼續(xù)使用JavaScript編寫代碼翩蘸,但是在處理HTML時使用JSX會感覺更自然。特別是對于那些不懂js的人淮逊,他們可以只修改HTML相關(guān)的部分催首。

JSX是一個類似于XML的JavaScript擴(kuò)展,可以配合一個簡單的語法編譯工具來使用它泄鹏。——深入淺出JSX

如果你想了解更多JSX的內(nèi)容备籽,查看文章JSX Looks Like An Abomination – But it’s Good for You舶治。

使用類

React中可以順暢地使用ES2015的Class語法。

class HelloMessage extends React.Component {  
  render() {
    return <div>Hello {this.props.name}</div>
  }
}

我們在高階組件和mixins之間更看重前者车猬,所以拋棄createClass更像是一個語法問題霉猛,而不是技術(shù)問題。(譯者注:在Class語法中诈唬,React組件的mixins方法將無法使用韩脏。)我們認(rèn)為使用createClass和React.Component沒有對錯之分。

屬性類型(PropType)

如果你以前不檢查props的類型铸磅,那么2016你應(yīng)該開始改正了赡矢。它會幫你節(jié)省未來很多時間杭朱,相信我。

MyComponent.propTypes = {  
  isLoading: PropTypes.bool.isRequired,
  items: ImmutablePropTypes.listOf(
    ImmutablePropTypes.contains({
      name: PropTypes.string.isRequired,
    })
  ).isRequired
}

是的吹散,同時也盡可能使用react-immutable-proptypes檢查Immutable.js的props弧械。

高階組件(Higher order components)

minins將死,ES6的Class將不對其進(jìn)行支持空民,我們需要尋找新的方法刃唐。

什么是高階組件?

PassData({ foo: 'bar' })(MyComponent)  

簡單地界轩,你創(chuàng)建一個從原生組件繼承下來的組件画饥,并且擴(kuò)展了原始組件的行為。你可以在多種場景來使用它浊猾,比如鑒權(quán):requireAuth({ role: 'admin' })(MyComponent)(在高階組件中檢查用戶權(quán)限抖甘,如果還沒有登錄就進(jìn)行跳轉(zhuǎn)),或者將組件與Flux/Redux的store相連通葫慎。

在RisingStack衔彻,我們也喜歡分離數(shù)據(jù)拉取和controller類的邏輯到高階組件中,這樣可以盡可能地保持view層的簡單偷办。

測試

好的代碼覆蓋測試是開發(fā)周期中的重要一環(huán)艰额。幸運(yùn)的是,React.js社區(qū)有很多這樣的庫來幫助我們椒涯。

組件測試

我們最喜愛的組件測試庫是AirBnb的enzyme柄沮。有了它的淺渲染特性,可以對組件的邏輯和渲染結(jié)果進(jìn)行測試逐工,非常棒對不對铡溪?它現(xiàn)在還不能替代selenium測試,但是將前端測試提升到了一個新高度泪喊。

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
})

看起來很清爽,不是嗎髓涯?

你使用chai來作為斷言庫嗎袒啼?你會喜歡chai-enyzime的。

Redux測試

測試一個reducer非常簡單纬纪,它響應(yīng)actions然后將原來的state轉(zhuǎn)為新的state:

it('should set token', () => {  
  const nextState = reducer(undefined, {
    type: USER_SET_TOKEN,
    token: 'my-token'
  })
 
  // immutable.js state output
  expect(nextState.toJS()).to.be.eql({
    token: 'my-token'
  })
})

測試actions也很簡單蚓再,但是異步actions就不一樣了。測試異步的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測試,請參考官方文檔问畅。

使用npm

雖然React.js并不依賴代碼構(gòu)建工具娃属,我們推薦WebpackBrowserify六荒,它們都具有npm出色的能力。Npm有很多React.js的package矾端,還可以幫助你優(yōu)雅地管理依賴掏击。

(請不要忘記復(fù)用你自己的組件,這是優(yōu)化代碼的絕佳方式秩铆。)

包大醒馔ぁ(Bundle size)

這本身不是一個React相關(guān)的問題,但多數(shù)人都會對其React進(jìn)行打包殴玛,所以我在這里提一下捅膘。

當(dāng)你對源代碼進(jìn)行構(gòu)建時,要保持對包大小的關(guān)注滚粟。要將其控制在最小體積篓跛,你需要思考如何require/import依賴。

查看下面的代碼片段坦刀,有兩種方式可以對輸出產(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的更新頻率比我們自己帶嗎低很多沐寺。

對輸出文件進(jìn)行hash命名(WebPack中的chunk hash),并使用長緩存盖奈,我們可以顯著地減少訪問用戶需要下載的代碼混坞。結(jié)合代碼懶加載,優(yōu)化效果可想而知钢坦。

如果你對WebPack還很陌生究孕,可以去看超贊的React webpack指南

組件級的hot reload

如果你曾使用livereload寫過單頁面應(yīng)用爹凹,你可能知道當(dāng)在處理一些與狀態(tài)相關(guān)的事情厨诸,一點(diǎn)代碼保存整個頁面就刷新了,這種體驗(yàn)有多煩人禾酱。你需要逐步點(diǎn)擊操作到剛才的環(huán)節(jié)微酬,然后在這樣的重復(fù)中奔潰。

在React開發(fā)中颤陶,是可以reload一個組件颗管,同時保持它的state不變——耶,從此無需苦惱滓走!

搭建hot reload垦江,可參考react-transform-boilerplate

使用ES2015

前面提到過搅方,在React.js中使用的JSX比吭,最終會被Babel.js進(jìn)行編譯绽族。

Babel logo in React.js Best Practices 2016
Babel logo in React.js Best Practices 2016

Bable的能力還不止這些,它可以讓我們在瀏覽器中放心地使用ES6/ES2015梗逮。在RisingStack项秉,我們在服務(wù)器端和客戶端都使用了ES2015的特性,ES2015已經(jīng)可以在最新的LTS Node.js版本中使用了慷彤。

代碼檢查(Linters)

也許你已經(jīng)對你的代碼制定了代碼規(guī)范娄蔼,但是你知道React的各種代碼規(guī)范嗎?我們建議你選擇一個代碼規(guī)范底哗,然后照著下面說的來做岁诉。

在RisingStack,我們強(qiáng)制將linters運(yùn)行在持續(xù)集成(CI)系統(tǒng)跋选,已經(jīng)git push功能上涕癣。查看pre-pushpre-commit

我們使用標(biāo)準(zhǔn)的JavaScript代碼風(fēng)格前标,并使用eslint-plugin-react來檢查React.js代碼坠韩。

(是的,我們已經(jīng)不再使用分號了)

GraphQL和Relay

GraphQL和Relay是相關(guān)的新技術(shù)炼列。在RisingStack只搁,我們不在生產(chǎn)環(huán)境使用它們,暫時保持關(guān)注俭尖。

我們寫了一個Relay的MongoDB ORM氢惋,叫做graffiti,可以使用你已有的mongoose models來創(chuàng)建GraphQL server稽犁。

如果你想學(xué)習(xí)這些新技術(shù)焰望,我們建議你去看看這個庫,然后寫幾個demo玩玩已亥。

這些React.js最佳實(shí)踐的核心點(diǎn)

有些優(yōu)秀的技術(shù)和庫其實(shí)跟React都沒什么關(guān)系熊赖,關(guān)鍵在于要關(guān)注社區(qū)都在做些什么。2015這一年陷猫,React社區(qū)被Elm架構(gòu)啟發(fā)了很多秫舌。

如果你知道其他2016年大家應(yīng)該使用的React.js工具,請留言告訴我們绣檬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市嫂粟,隨后出現(xiàn)的幾起案子娇未,更是在濱河造成了極大的恐慌,老刑警劉巖星虹,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件零抬,死亡現(xiàn)場離奇詭異镊讼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)平夜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門蝶棋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人忽妒,你說我怎么就攤上這事玩裙。” “怎么了段直?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵吃溅,是天一觀的道長。 經(jīng)常有香客問我鸯檬,道長决侈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任喧务,我火速辦了婚禮赖歌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘功茴。我一直安慰自己庐冯,他們只是感情好肄扎,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般痰娱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天拳亿,我揣著相機(jī)與錄音肺魁,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛酗捌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哪廓,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼哆料,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了典阵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤减江,失蹤者是張志新(化名)和其女友劉穎份企,沒想到半個月后司志,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腰根,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年球拦,在試婚紗的時候發(fā)現(xiàn)自己被綠了愧膀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡捡絮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出半火,到底是詐尸還是另有隱情季俩,我是刑警寧澤钮糖,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站酌住,受9級特大地震影響店归,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜酪我,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一消痛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧都哭,春花似錦秩伞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至汇陆,卻和暖如春怒炸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背毡代。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工阅羹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人教寂。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓捏鱼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親酪耕。 傳聞我的和親對象是個殘疾皇子导梆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容