你們夥兒們,又見面了?。 自上次Byemess Todo以後,以爲自身不足仍是挺多的,期間又萌生了一些將它重構加上更多新特性的想法,以後技術磨鍊一陣再來好好改造它。對於Learn by doing這種事情,一次就會上癮啊有木有❤️,因而乎本着繼續精進練習React技術棧,以及實踐更多相關技術的初衷,besides that,本身還想再準備一個小項目來爲找工做打底氣,因而乎就有了CoderPad。react
在最開始的時候,是想作一個催稿app,又是一個集成的idea:提供分類書單,能夠記錄閱讀狀況,而後根據這個狀況設定或者後臺計算智能推薦:什麼時候去寫一篇相關的博客(技術博客),固然寫做也是在這個app裏完成,而後自動部署至github page。 名字我都想好了,就叫催乎...(知乎er們懂的),奈何這是個大工程啊... 我就造出了這麼個只有編輯,閱讀的閹割版。 另外關於寫完markdown直接部署生成靜態博客的app我推薦好基友的Page.qy => ? 無代碼建站,基於Node.js,React和Electron,很用心的app,向他學習之,他立刻又會寫出一個UI逆天美的音樂播放器了,大家能夠關注他。ios
Markdown: 支持本地緩存,保存/刪除/查看/下載,追求極簡。
nginx
NewsFeed: 集成v2ex,HackerNews-Top Stories, Github-Trending
git
Music: 暫未施工github
老朋友React全家桶: 對於這塊,值得一提的是react router v4,相對於v3的巨大改動,extremely make sense. 讓route與組件化思想更貼切,有種幻覺:定義子route更加爲所欲爲了。至於爲何... 請君上手感覺。express
Immutable: 有一些細微的坑,主要體如今數據類型轉化上,immutable會將原生JS數據類型進行包裝,如Map,List,在對它們進行提取的時候須要注意是否已經轉化爲原生JS,不然容易出錯。 個人建議就是時刻注意提取的數據是什麼類型,結合PropTypes進行參數檢測,出錯時先console看看,通常很快能夠解決。 對於多層對象嵌套的時候,爲了保險,手動將被嵌套的對象進行指定類型轉化,好比{ list: [] } => { list:Immutable.List([]) }
,若是要偷懶的話能夠直接使用fromJS
,可是這個方法滲透性強,會將全部內嵌結構進行轉化,在本項目的後期重構裏就遇到了子數組遍歷出來全是immutable object的狀況,須要手動再次轉化,非常噁心。 這些缺點在redux文檔裏也有表述,在具體實踐後纔能有更直觀的理解。 參照: What are the issues with using Immutable.JS?.但不能否認Immutable.js很是符合react的思想,都在處理大規模數據時彰顯優點。redux
Reselect:它用來替代咱們手寫的state selector, 它的主要思想: state1 + state2 => state3, 緩存先決state,它們若是計算結果是相同的,就使用緩存結果不去改變最終state,一樣也是immutable思想。 在結合immutable.js的時候,也是坑啊,仍是那個老問題,數據類型,state嵌套越深,越麻煩。 因此,如今明白爲何強調Redux State扁平化了吧?axios
Redux Saga: Oh my.. 無比親切,至於緣由: 我寫過這麼一篇文章:From Iterator To Async. Saga致力於解決複雜場景下的異步流程控制,用它來管理action觸發,酸爽無比。 畢竟控制異步流程這種成就在JS話題下自己就是爽的不要不要的。 本質是使用generator,對於理解CO庫的同窗們,掌握saga不在話下。在操做極其頻繁的場景下(好比遊戲),你會感覺到他的威力。 推薦一篇文章: Async operations using redux-saga, 在本項目裏我主要用它來控制news數據的拉取,採用axios.
Styled Components: 老朋友,更新了2.0版本,一樣配合styled-props,效果拔羣。 至於一些宏觀上的樣式設置,的確不如直接寫CSS那麼直觀。 我採用的方法是,特性按組件寫,通性和一些涉及多層級樣式都放在wrapper裏。 也許單獨使用styled-components並不能發揮出色,配合傳統CSS寫法,應該能夠相得益彰。
ref: 對於ref的感受一直是又愛又恨,畢竟在react以前,dom操做被咱們玩的飛起,而react官方的態度一直是不建議使用。 在此次的項目中,markdown editor處的textarea我便採用了Uncontrolled的形式,使用ref保存dom引用。 初衷是爲了對頻繁的內容變更進行debounce處理,當編輯暫停時才觸發一次內容state更新。 隨着組件的增長,在一個嵌套達到3層的modal組件裏,須要對textarea的value進行重置操做,好了,這下我得從父組件一層層的把這個ref傳進去。 那感受簡直不能再糟.... 一剎那感受官方文檔就像和善的老司機,句句肺腑之言啊! 不過在你真的遇到這個坑前,是不會有多深的感覺的。 要解決這個噁心的傳遞,只有採用controlled形式,onChange監聽,value直接連接state.
Perf: 做爲性能測量的利器,測試結果讓我發現styled-components的消耗是可觀的,尤爲是更新到v2.0版本後。在其餘方面,因爲本項目裏的newsFeed可能會涉及頻繁點擊切換路徑的狀況,爲了防止無謂的重複渲染,給全部presentational components都設置爲PureComponent, 接着在一些只須要更新一次的組件裏手寫shouldComponentUpdate
, 仍是強調一點: 必須十分清楚傳入的參數,以及其結構,並考慮這個結構是否在生產環境中有變化的可能致使判斷失效。 還有個值得注意的問題是react-router-v4裏的NavLink檢測location渲染當前激活地址的link(activeClassName屬性)時,注意組件是不是PureComponent, 若是是,必須在父組件傳入location,不然PureComponent的shouldComponentUpdate
將會斷定參數無變化,從而block掉link的動態渲染。參照: Dealing with Update Blocking
Server Side: 因爲是使用leancloud部署,用node環境,爲了解決v2ex api的跨域問題,本身寫了一套請求轉發,可是問題來了: 單頁APP裏爲保證刷新後不出現cannot get等問題,必須寫上一條app.get('*', (req, res) => {res.sendFile('index.html的路徑')} )
, 這就很麻煩了,後來通過請教,用正則過濾了請求轉發涉及的路徑,就避免了路徑全局攔截。可是! 這樣刷新後,又會遇到cannot get的問題了。 由於再次刷新時url已經變化,瀏覽器會去請求這個地址,然後臺並無提供此路徑的響應。 最好的辦法是使用nginx部署環境。(express難道就沒辦法? 仍是我服務端知識短淺啊...要惡補) 另一個問題: 生產環境和部署環境下因爲使用了不一樣的請求地址,返回的數據的結構存在微小差別,以本項目爲例,請求v2ex topic在生產環境下數據是res.data
,而到了部署環境下因爲使用了本身設置的請求地址,返回的數據成了res.data[0]
,找了好久才發現問題,值得注意。
Cancellation: 在newsfeed裏頻繁切換頁面時還有一個問題: 也許下一個頁面呈現時,上一個頁面中觸發的fetch操做還沒執行完畢。舉個例子: 我進入了v2ex的頁面,此時組件拉取新聞信息,接着我幾乎不等待便切換至github,此時對於v2ex的拉取還在進行。這就是一種浪費了。 爲了解決它,起初我嘗試用saga結合react-router-redux裏提供的LOCATION_CHANGE
action來做爲斷定取消以前未完成fetch的標誌。 測試發現就算我點擊的是同一個link,依然會觸發LOCATION_CHANGE
,(真坑啊,徹底不符合直覺好麼!?)那麼有這麼一個場景: 當你進入hackerNews等待數據返回,因爲時間較久,你不耐煩的再次點擊了hackerNews的Link,Boom~~! LOCATION_CHANGE
dispatched. 因而乎你的fetch被取消了...,因此用LOCATION_CHANGE
做爲斷定標誌在首次拉取這個場景下是不可行的(論corner case重要性..), 後來想出來的解決辦法是在三塊新聞組件的componentDidMount
的頂部dispatch一個STOP_FETCH
action,而後將斷定取消的標誌改成:STOP_FETCH
,算是解決了,可總感受有點暴力,由於一旦組件變多,將要手動。接下來將繼續思考更優雅的解決方案,若是大神們有答案,請告知。
最大的收穫: 主動找上問題,而不是問題找上你。 不折騰,不踩坑,進步頗微。
當container變多時,直接將container component做爲單位,單獨設立目錄,而後放置對應的components/styled-components/reducer/action. 這就是按feature組織目錄的方法。 細緻的拆分,解耦性更好,以container component爲單位進行修改時,大大下降誤傷率的同時,隔離無關的信息。
大概總結出一個Learn by doing的心路歷程:
被何嘗試的技術吸引,而且有了下一個project的idea
嘗試拆分所需技能,分紅組塊(裂牆推薦知乎金旭亮老師組塊學習論)
漫長的學習過程: 讀文檔,找樣例,寫小demo倒騰API。因爲組塊積累未徹底,因此沒法對project全面下手,天然會很煩躁,而且踏出了溫馨區,接收更多的信息。
組塊知識積累完畢,project開始施工: 從最簡功能需求開始,不斷增長新feature: problem -> google -> resolve.
Project成型,評估,修正,改進,more problem come in.
項目總結。而後享受一下獨立完成project的成就感。同時也會深入理解本身的不足,爲本身的技術精進之路指明瞭方向。
以project爲單位,循環以上步驟。
最後的領悟: 我早幾年幹什麼去了... 捶胸淚目ing。
將來可能會補上的:
白噪音組合播放
番茄鍾
音樂部分(哈哈哈偷懶了時間很少了,趕忙找工做。)
做爲一名新人,還請你們多多指教。一樣無恥的求star,2333。